POJ1275 Cashier Employment 【二分 + 差分约束】

题目链接

POJ1275

题解

显然可以差分约束
我们记\(W[i]\)\(i\)时刻可以开始工作的人数
\(s[i]\)为前\(i\)个时刻开始工作的人数的前缀和

每个时刻的要求\(r[i]\),可以通过如下限制满足:

\[s[i] - s[i - 8] \ge r[i] \]

\[0 \le s[i] - s[i - 1] \le W[i] \]

但是\(i - 8\)可能为负,回到上一天的时刻,导致区间不连续,不好处理
我们可以二分答案\(sum\)
\(i < 8\)的部分改为:

\[s[i + 16] - s[i] \le sum - R[i] \]

再加一个

\[s[24] - s[0] \ge sum \]

这样就可以了

#include<algorithm>
#include<iostream>
#include<cstring>
#include<cstdio>
#include<cmath>
#include<map>
#define Redge(u) for (int k = h[u],to; k; k = ed[k].nxt)
#define REP(i,n) for (int i = 1; i <= (n); i++)
#define mp(a,b) make_pair<int,int>(a,b)
#define cls(s) memset(s,0,sizeof(s))
#define cp pair<int,int>
#define LL long long int
using namespace std;
const int maxn = 105,maxm = 1000005,INF = 1000000000;
inline int read(){
	int out = 0,flag = 1; char c = getchar();
	while (c < 48 || c > 57){if (c == '-') flag = -1; c = getchar();}
	while (c >= 48 && c <= 57){out = (out << 3) + (out << 1) + c - 48; c = getchar();}
	return out * flag;
}
int h[maxn],ne;
struct EDGE{int to,nxt,w;}ed[maxm];
inline void build(int u,int v,int w){
	ed[++ne] = (EDGE){v,h[u],w}; h[u] = ne;
}
int n,R[50],W[50];
int d[maxn],vis[maxn],cnt[maxn];
int q[maxm],head,tail;
bool spfa(){
	for (int i = 0; i <= 24; i++) d[i] = -INF,vis[i] = false,cnt[i] = 0;
	d[0] = 0; q[head = tail = 0] = 0;
	int u;
	while (head <= tail){
		u = q[head++];
		vis[u] = false; cnt[u]++;
		if (cnt[u] >= 25) return false;
		Redge(u) if (d[to = ed[k].to] < d[u] + ed[k].w){
			d[to] = d[u] + ed[k].w;
			if (!vis[to]) vis[to] = true,q[++tail] = to;
		}
	}
	return true;
}
bool check(int sum){
	for (int i = 1; i <= 24; i++) if (R[i] > sum) return false;
	cls(h); ne = 0;
	for (int i = 1; i < 8; i++) build(i + 16,i,R[i] - sum);
	for (int i = 8; i <= 24; i++) build(i - 8,i,R[i]);
	for (int i = 1; i <= 24; i++){
		build(i - 1,i,0);
		build(i,i - 1,-W[i]);
	}
	build(0,24,sum);
	return spfa();
}
int main(){
	int T = read();
	while (T--){
		for (int i = 1; i <= 24; i++)
			R[i] = read(),W[i] = 0;
		n = read(); int x;
		REP(i,n){
			x = read() + 1;
			W[x]++;
		}
		int l = 0,r = n,mid,flag = false;
		while (l < r){
			mid = l + r >> 1;
			if (check(mid)) r = mid,flag = true;
			else l = mid + 1;
		}
		if (!flag) puts("No Solution");
		else printf("%d\n",l);
	}
	return 0;
}

posted @ 2018-06-09 19:59  Mychael  阅读(120)  评论(0编辑  收藏  举报