题意:一家商店在每个小时都需要至少di个人值班,现在有n个人,第j个人可以在fj开始上班,连续工作8个小时,问你要满足商店上班的条件至少需要雇佣多少个人
原题连接:http://poj.org/problem?id=1275
一道比较复杂的查分约束,一开始想着写出每个小时的约束条件,后来发现根本就是牛头不对马嘴。
正解应该是这样:
设di是第i小时需要的人数,fi是第i小时可以雇佣的最大人数,si是第0-i小时雇佣的人数的和
可以建立这样的约束
si-si-1 <= fi 人数最多不能超过来应聘的
si-si-1 >= 0 人数不能为负值
si-s(i-8)>= di i>=8 八小时内雇佣的人数大于当前时间点需要的人数
si-s(i+16)>=di-s24 1<=i<8
但是到了这里约束出现了问题,就是s24是一个未知数,而s24就是我们要求的和,我们要求一个最小的24也就是说
ans <= s24 di - ans >= di - s24,显然要有 si-s(i+16)>=di-ans成立
并且为了保证ans<=s24 s24=s24-s0所以有约束ans<=s24-s0
所以只需要通过枚举ans,然后看差分约束是否可以得到解来判断可行性,枚举的方式用二分即可。
判断可行性使用spfa或者bellmanford就可以
#include <cstdio> #include <cstring> #include <cmath> #include <algorithm> #include <climits> #include <string> #include <iostream> #include <map> #include <cstdlib> #include <list> #include <set> #include <queue> #include <stack> using namespace std; typedef long long LL; const int maxn = 25; const int maxm = 4e3; const int INF = INT_MAX / 4; int first[maxn],nxt[maxm],w[maxm],v[maxm]; int d[maxn],n,cnt[maxn],ecnt,qcnt[maxn],a[maxn]; bool inq[maxn]; void adde(int a,int b,int c) { w[ecnt] = c; v[ecnt] = b; nxt[ecnt] = first[a]; first[a] = ecnt; ecnt++; } bool bellmanford() { for(int i = 0;i <= 24;i++) d[i] = INF; d[0] = 0; for(int i = 0;i <= 24;i++) { for(int j = 0;j <= 24;j++) { for(int k = first[j];k != -1;k = nxt[k]) { if(d[v[k]] > d[j] + w[k]) { d[v[k]] = d[j] + w[k]; } } } } for(int i = 0;i <= 24;i++) { for(int j = first[i];j != -1;j = nxt[j]) { if(d[v[j]] > d[i] + w[j]) return false; } } return true; } bool ok(int sum) { int necnt = ecnt,tmpnxt[maxm],tmpfirst[maxn]; memcpy(tmpnxt,nxt,sizeof(nxt)); memcpy(tmpfirst,first,sizeof(first)); for(int i = 0;i < 24;i++) { int j = (i + 7) % 24 + 1; if(j > i) adde(j,i,-a[j]); else adde(j,i,sum-a[j]); } //adde(0,24,sum); adde(24,0,-sum); bool ret = bellmanford(); ecnt = necnt; memcpy(nxt,tmpnxt,sizeof(nxt)); memcpy(first,tmpfirst,sizeof(first)); return ret; } void solve() { int l = 0,r = n; while(l < r) { int mid = (l + r) >> 1; //printf("now is %d %d %d ",l,r,mid); if(ok(mid)) r = mid; else l = mid + 1; } if(!ok(l)) puts("No Solution"); else printf("%d ",l); } int main() { //freopen("/tmp/in.txt","r",stdin); int T; scanf("%d",&T); for(int kase = 1;kase <= T;kase++) { ecnt = 0; memset(first,-1,sizeof(first)); memset(nxt,-1,sizeof(nxt)); memset(cnt,0,sizeof(cnt)); for(int i = 1;i <= 24;i++) { scanf("%d",&a[i]); } scanf("%d",&n); for(int i = 1;i <= n;i++) { int str; scanf("%d",&str); cnt[str + 1]++; } for(int i = 1;i <= 24;i++) { adde(i - 1,i,cnt[i]); adde(i,i - 1,0); } solve(); } return 0; }