记录编号 290266 评测结果 AAAAAAAAAA
题目名称 [POJ1275]出纳员的雇佣 最终得分 100
用户昵称 GravatarSky_miner 是否通过 通过
代码语言 C++ 运行时间 0.008 s
提交时间 2016-08-06 06:08:40 内存使用 0.29 MiB
显示代码纯文本
/*
	设num[ i ]为i时刻能够开始工作的人数,x[ i ]为 第 i 时刻实际雇佣的人数,那么x[ I ]<=num[ I ]。 
	设r[ i ](输入的每一时刻所需的人数)为i时刻至少需要工作的人数,于是有如下关系: 
	x[ I-7 ]+x[ I-6 ]+x[ I-5 ]+x[ I-4 ]+x[ I-3 ]+x[ I-2 ]+x[ I-1 ]+x[ I ]>=r[ I ]
	设s[ I ]=x[ 1 ]+x[ 2 ]…+x[ I ],得到 
	0<=s[ I ]-s[ I-1 ]<=num[ I ], 0<=I<=23 
	s[ I ]-s[ I-8 ]>=r[ I ], 8<=I<=23    建立关系
	s[ 23 ]+s[ I ]-s[ I+16 ]>=r[ I ], 0<=I<=7 建立可以循环的关系 
	对于以上的几组不等式,我们采用一种非常笨拙的办法处理这一系列的不等式(其实也是让零乱的式子变得更加整齐,易于处理)。
	首先我们要明白差分约束系统的应用对象(它通常针对多个二项相减的不等式的)
	于是我们将上面的所有式子都转化成两项未知项在左边,另外的常数项在右边,且中间用>=连接的式子,即:
	s[ I ] - s[ I-1 ] >= 0            (0<=I<=23) 
	s[ I-1 ] - s[ I ] >= -num[ I ]       (0<=I<=23) 
	s[ I ]-s[ I-8 ]>=r[ I ]         (8<=I<=23) 
	s[ I ]-s[ I+16 ]>=r[ I ]-s[ 23 ]  (0<=I<= 7)
	S[23] - 0 >= sum;sum为雇佣的出纳员总数
*/
//好麻烦的关系转换,,,对差分约束不会再有爱了。。。
#include <cstdio>
#include <cstring>
using namespace std;
template<typename T>inline void read(T &x){
	x=0;char ch;bool flag = false;
	while(ch=getchar(),ch<'!'); if( ch == '-' ) ch=getchar(),flag = true;
	while(x=10*x+ch-'0',ch=getchar(),ch>'!');if( flag ) x=-x;
}
int n,m,p,ecnt,T;
int dis[30],cnt[30],r[30],t[30];
const int INF = 1e9;
int to[100],head[30],he[30],ne[100]={0},w[100]={0};
inline void add(int u,int v,int c){
	to[++ecnt] = v;
	w[ecnt] = c;
	ne[ecnt] = head[u];
	head[u] = ecnt;
}
int Q[100],qhead = 1,qtail = 99,size = 0;
bool flag[100];
inline int top(){
	int x = Q[qhead];
	if( ++qhead == 100 )qhead=1;
	--size;
	flag[x] = false;
	return x;
}
inline void push_front(int x){
	flag[x] = true;
	++size;
	if( !(--qhead) ) qhead=99;
	Q[ qhead ] = x;
}
inline void push_back(int x){
	flag[x] = true;
	++size;
	if(++qtail == 100) qtail = 1;
	Q[qtail] = x;
}
inline bool spfa(int mid){
	for(int i = 0;i <= 24; ++i) dis[i] = -INF,cnt[i] = 0;
	cnt[0] = 1;dis[0] = 0;
	push_back(0);
	while( size ) for(int x=top(),i=head[x];i;i=ne[i])
	if( dis[ to[i] ] < dis[x] + w[i]){
		dis[ to[i] ] = dis[x] + w[i];
		if( !flag[to[i]] ){
			if( ++cnt[to[i]] > 24) return 0;
			if( size && dis[Q[qhead]] <= dis[to[i]]) push_front(to[i]);
			else push_back(to[i]);
		}
	}
	if(dis[24] == mid) return 1;
	return 0;
}
 
int main(){
	freopen("cashieremployment.in","r",stdin);
	freopen("cashieremployment.out","w",stdout);
	read<int>(T);
	while(T--){
		for(int i=1;i<=24;++i) read<int>(r[i]);
		for(int i=0;i<=24;++i) t[i] = head[i] = 0;
		read<int>(n);
		ecnt = 0;
		int x;
		for(int i=1;i<=n;++i)  read<int>(x),t[x+1]++;
		for(int i=1;i<=24;++i) add(i-1,i,0),add(i,i-1,-t[i]);
		for(int i=0;i<=24;++i) he[i] = head[i];
		int ans = -1,L = 0,R = n;
		while(L<=R){
			int mid = (L+R)>>1;ecnt=48;
			for(int i=0;i<=24;++i)head[i]=he[i];
			add(0,24,mid);
			for(int i=1;i<=8;++i)add(i+16,i,r[i]-mid);
			for(int i=9;i<=24;++i)add(i-8,i,r[i]);
			if(spfa(mid)) ans = mid,R = mid-1;
			else L=mid+1;
		}
		if(ans == -1) printf("No Solution\n");
		else printf("%d\n",ans);
	}
	return 0;
}