【POJ1275】Cashier Employment
题目:
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. Input The first line of input is the number of test cases for this problem (at most 20). Each test case starts with 24 integer numbers representing the R(0), R(1), ..., R(23) in one line (R(i) can be at most 1000). Then there is N, number of applicants in another line (0 <= N <= 1000), after which come N lines each containing one ti (0 <= ti <= 23). There are no blank lines between test cases.
Output For each test case, the output should be written in one line, which is the least number of cashiers needed.
If there is no solution for the test case, you should write No Solution for that case. Sample Input 1 1 0 1 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 5 0 23 22 1 10 Sample Output 1 |
题意:
德黑兰的一家每天24小时营业的超市,需要一批出纳员来满足它的需求。超市经理雇佣你来帮他解决一个问题————超市在每天的不同时段需要不同数目的出纳员(例如,午夜只需一小批,而下午则需要很多)来为顾客提供优质服务,他希望雇佣最少数目的纳员。
超市经历已经提供一天里每一小时需要出纳员的最少数量————R(0),R(1),...,R(23)。R(0)表示从午夜到凌晨1:00所需要出纳员的最少数目;R(1)表示凌晨1:00到2:00之间需要的;等等。每一天,这些数据都是相同的。有N人申请这项工作,每个申请者i在每天24小时当中,从一个特定的时刻开始连续工作恰好8小时。定义ti(0<=ti<=23)为上面提到的开始时刻,也就是说,如果第i个申请者被录用,他(或她)将从ti时刻开始连续工作8小时。
试着编写一个程序,输入R(i),i=0,...,23,以及ti,i=1,...,N,它们都是非负整数,计算为满足上述限制需要雇佣的最少出纳员数目、在每一时刻可以有比对应R(i)更多的出纳员在工作。
分析:
因为一开始就知道这是一道差分约束题,于是就往这方面想了。然而可爱的是,还是没有想出来。TAT~
其实就是不会搞循环的情况,感觉我的不等式这样子就有三个元了TAT。我们设xi为我们选择了xi个在i时间开始工作的员工,先不考虑循环的情况,那么对于时间点i,那么在时间点i这个时刻正在工作的人数为x[i-7]+x[i-6]+...x[i],用sum数组维护x,即为sum[i]-sum[i-8]。于是我们得到不等式sum[i]-sum[i-8]>=need[i]。(need[i]为题目输入的时间点i需要的员工数)
循环的情况怎么搞呢?对于i(i<=7),那么后面某一段时间开始工作的员工也会影响答案,那么我们得到的不等式就是sum[24]-sum[i+16]+sum[i]>=need[i](这里的时间点我从1~24考虑)。这里有三个未知数啊,怎么办呢,于是我想了很久没有想出来。
竟然是!!二分枚举一下sum[24]就好了,那么就把sum[24]看成常数把!!看到这里,我哭了,世界上竟有如此低智商的我!!
好吧...因为如果我们雇x个人可以搞定全部,那么雇多一点人也可以的嘛,这就是某种单调性,于是我们可以二分。最后再连一条24->0的边权为-sum[24]就可以了。
差分约束...
对了,还有一些隐性条件,千万不要漏,上一题中已经说过了。
eg. x[i]-x[i-1]>=0
代码如下:
1 #include<cstdio> 2 #include<cstdlib> 3 #include<cstring> 4 #include<iostream> 5 #include<algorithm> 6 using namespace std; 7 #include<queue> 8 #define Maxn 30 9 10 int a[Maxn],sum[Maxn]; 11 int first[Maxn],dis[Maxn],cnt[Maxn]; 12 bool inq[Maxn]; 13 14 struct node 15 { 16 int x,y,c,next; 17 }t[Maxn*4];int len; 18 19 void ins(int x,int y,int c) 20 { 21 t[++len].x=x;t[len].y=y;t[len].c=c; 22 t[len].next=first[x];first[x]=len; 23 } 24 25 26 queue<int > q; 27 bool spfa(int s) 28 { 29 while(!q.empty()) q.pop(); 30 memset(dis,63,sizeof(dis)); 31 memset(inq,0,sizeof(inq)); 32 memset(cnt,0,sizeof(cnt)); 33 dis[s]=0;inq[s]=1;q.push(s); 34 while(!q.empty()) 35 { 36 int x=q.front();q.pop();inq[x]=0; 37 for(int i=first[x];i;i=t[i].next) 38 { 39 int y=t[i].y; 40 if(dis[y]>dis[x]+t[i].c) 41 { 42 dis[y]=dis[x]+t[i].c; 43 if(!inq[y]) 44 { 45 q.push(y); 46 inq[y]=1; 47 if(++cnt[y]>25) return 0; 48 } 49 } 50 } 51 } 52 return 1; 53 } 54 55 bool check(int x) 56 { 57 for(int i=1;i<=7;i++) t[len-8+i].c=x-a[i]; 58 t[len].c=-x; 59 return spfa(0); 60 } 61 62 void ffind(int l,int r) 63 { 64 //check(1); 65 while(l<r) 66 { 67 int mid=(l+r)>>1; 68 if(check(mid)) r=mid; 69 else l=mid+1; 70 } 71 printf("%d\n",l); 72 } 73 74 int main() 75 { 76 int T; 77 scanf("%d",&T); 78 while(T--) 79 { 80 int x,n; 81 memset(sum,0,sizeof(sum)); 82 for(int i=1;i<=24;i++) scanf("%d",&a[i]); 83 scanf("%d",&n); 84 for(int i=1;i<=n;i++) 85 { 86 int x; 87 scanf("%d",&x); 88 sum[x+1]++; 89 } 90 len=0; 91 memset(first,0,sizeof(first)); 92 for(int i=1;i<=24;i++) ins(i-1,i,sum[i]); 93 for(int i=1;i<=24;i++) ins(i,i-1,0); 94 for(int i=8;i<=24;i++) ins(i,i-8,-a[i]); 95 for(int i=1;i<=7;i++) ins(i,16+i,0); 96 ins(24,0,0); 97 if(!check(n)) {printf("No Solution\n");continue;} 98 ffind(0,n); 99 } 100 return 0; 101 }
2016-04-12 13:51:47