POJ 1275 Cashier Employment 差分约束+二分答案
题意:一家商店在每个小时都需要至少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\n",l,r,mid);
if(ok(mid)) r = mid;
else l = mid + 1;
}
if(!ok(l)) puts("No Solution");
else printf("%d\n",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;
}

浙公网安备 33010602011771号