POJ1275 Cashier Employment

Cashier Employment

给出24个数,第i个数表示在(i,i+1)小时内需要的人数,之后m个数,代表m个人前来应聘,其中每个人工作连续的8小时,给出应聘的人开始工作的时间,问最少需要雇佣的人数(可以在某个时间段中人数多于需要的人数)

题解

参照刀刀狗0102的题解。

问题分析:因为二十四小时是循环的,所以这是一个环,这题不能只用前缀和表示关系。解决办法是枚举(二分)答案,然后连特殊边(边权根据枚举的答案变化)解决问题。

差分约束:

  1. 题目需要求什么,就找什么之间的关系(二项式),比如,题目求雇佣的人数,就找出雇佣人数之间的关系,s[i]代表从0到i一共雇佣的人数
  2. 注意0的问题,和总和的问题。
  3. 判断的问题,不能存在环,和不能违背要求的值

那么归结关系有
s[i]:1到i时刻雇佣的总人数。
c[i]:i时刻;来应聘的人数。
r[i]:i时刻需要的人数。

设需要的人数为sum,即枚举的答案。

  1. 实际问题
    0 <= s[i] - s[i-1] <= h[i] ;
  2. 总数
    s[24] - s[0] >= sum
  3. 分类讨论约束
    s[i] - s[i-8] >= r[i] (i >= 8)
    sum - s[i+16] + s[i] >= r[i] (i < 8)

对上面的条件整理,然后求最短路,如果没有负环那么就有解。

#include<iostream>
#include<cstring>
#include<queue>
#define rg register
#define il inline
#define co const
template<class T>il T read(){
    rg T data=0,w=1;rg char ch=getchar();
    for(;!isdigit(ch);ch=getchar())if(ch=='-') w=-w;
    for(;isdigit(ch);ch=getchar()) data=data*10+ch-'0';
    return data*w;
}
template<class T>il T read(rg T&x) {return x=read<T>();}
typedef long long ll;
using namespace std;

co int N=1e3+1;
int n,r[N],c[N],d[N],s[N];
int head[N],edge[N],next[N],leng[N],tot;
bool v[N];

il void add(int x,int y,int z){
	edge[++tot]=y,leng[tot]=z,next[tot]=head[x],head[x]=tot;
}
int spfa(int now){
	for(int i=1;i<=7;++i) leng[head[i]]=now-r[i];
	leng[head[24]]=-now;
	memset(d,0x3f,sizeof d);
	memset(s,0,sizeof s);
	queue<int> q;
	for(int i=0;i<=24;++i) q.push(i),d[i]=0,v[i]=1;
	while(q.size()){
		int x=q.front();q.pop();
		v[x]=0;
		for(int i=head[x];i;i=next[i]){
			int y=edge[i],z=leng[i];
			if(d[y]>d[x]+z){
				d[y]=d[x]+z,s[y]=s[x]+1;
				if(s[y]>25) return 0;
				if(!v[y]) q.push(y),v[y]=1;
			}
		}
	}
	return 1;
}
void Cashier_Employment(){
	for(int i=1;i<=24;++i) read(r[i]);
	read(n),memset(c,0,sizeof c);
	for(int i=1;i<=n;++i) ++c[read<int>()+1];
	tot=0,memset(head,0,sizeof head);
	for(int i=1;i<=24;++i){
		add(i-1,i,c[i]);
		add(i,i-1,0);
	}
	for(int i=8;i<=24;++i) add(i,i-8,-r[i]);
	for(int i=1;i<=7;++i) add(i,i+16,0); // changeable length
	add(24,0,0);
	for(int i=1;i<=n;++i)
		if(spfa(i)) return printf("%d\n",i),void();
	puts("No Solution");
}
int main(){
	for(int t=read<int>();t--;) Cashier_Employment();
	return 0;
}

posted on 2019-06-18 15:08  autoint  阅读(118)  评论(0)    收藏  举报

导航