Description
A supermarket in Tehran is open 24 hours a day every day and needs a number of cashiers to fit its need. The supermarket manager has hired you to help him, solve his problem. The problem is that the supermarket needs different number of cashiers at different times of each day (for example, a few cashiers after midnight, and many in the afternoon) to provide good service to its customers, and he wants to hire the least number of cashiers for this job.
The manager has provided you with the least number of cashiers needed for every one-hour slot of the day. This data is given as R(0), R(1), ..., R(23): R(0) represents the least number of cashiers needed from midnight to 1:00 A.M., R(1) shows this number for duration of 1:00 A.M. to 2:00 A.M., and so on. Note that these numbers are the same every day. There are N qualified applicants for this job. Each applicant i works non-stop once each 24 hours in a shift of exactly 8 hours starting from a specified hour, say ti (0 <= ti <= 23), exactly from the start of the hour mentioned. That is, if the ith applicant is hired, he/she will work starting from ti o'clock sharp for 8 hours. Cashiers do not replace one another and work exactly as scheduled, and there are enough cash registers and counters for those who are hired.
You are to write a program to read the R(i) 's for i=0...23 and ti 's for i=1...N that are all, non-negative integer numbers and compute the least number of cashiers needed to be employed to meet the mentioned constraints. Note that there can be more cashiers than the least number needed for a specific slot.
translation
有一个超市,在24小时对员工都有一定需求量,表示为 (R[i]),意思为在i这个时间至少要有i个员工,现在有n个员工来应聘,每一个员工开始工作的时间为ti,并持续8小时,问最少需要多少员工才能达到每一个时刻的需求
solution
**正解:差分约束
假设我们在前i个时刻设置了si个员工,那么最直接的限制条件就是 $$s[i]-s[i-8]>=R[i]$$
其中s[24]是答案,我们不确定,需要二分答案
然后就是细节的限制:
我们设在i这个时间开始的员工量为pi,mid为二分的答案呢
值得注意的是:差分约束的条件一般缺一不可**
#include <algorithm>
#include <iostream>
#include <cstdlib>
#include <cstring>
#include <cstdio>
#include <cmath>
#define RG register
#define il inline
#define iter iterator
#define Max(a,b) ((a)>(b)?(a):(b))
#define Min(a,b) ((a)<(b)?(a):(b))
using namespace std;
const int N=55,M=10005;
int head[N],to[M],dis[M],nxt[M],num=0,n,r[N],p[N];
il void link(int x,int y,int z){
nxt[++num]=head[x];to[num]=y;head[x]=num;dis[num]=z;}
int f[N];bool vis[N];
void Clear(){
for(int i=0;i<N;i++)head[i]=f[i]=vis[i]=0;
num=0;
}
il int dfs(int x){
vis[x]=1;
for(RG int i=head[x];i;i=nxt[i]){
int u=to[i];
if(f[x]+dis[i]<f[u]){
if(vis[u])return false;
f[u]=f[x]+dis[i];
if(!dfs(u))return false;
}
}
vis[x]=0;
return true;
}
bool check(int mid){
Clear();
for(int i=1;i<=24;i++)
link(i,i-1,p[i]),link(i-1,i,0);
for(int i=1;i<=7;i++)
link(i+16,i,mid-r[i]);
for(int i=8;i<=24;i++)
link(i-8,i,-r[i]);
link(24,0,mid);link(0,24,-mid);
for(int i=0;i<=24;i++)
if(!dfs(i))return false;
return true;
}
void work()
{
int x;
for(int i=1;i<=24;i++)
scanf("%d",&r[i]),p[i]=0;
scanf("%d",&n);
for(int i=1;i<=n;i++){
scanf("%d",&x);
p[x+1]++;
}
int l=0,r=n,mid,ans=-1;
while(l<=r){
mid=(l+r)>>1;
if(check(mid))ans=mid,r=mid-1;
else l=mid+1;
}
if(ans==-1)puts("No Solution");
else printf("%d
",ans);
}
int main()
{
int T;cin>>T;
while(T--)work();
return 0;
}