hdu 1529 Cashier Employment(差分约束)

Cashier Employment

Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/32768 K (Java/Others)
Total Submission(s): 1214    Accepted Submission(s): 537


Problem 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
 

 

Source
 

较为难的差分约束系统。
首先我们要确定我们要求解的东西,才能依次建立不等式。
显然我们要求解第0-23小时每个小时加入的人手的和。
对于求解的答案,我们设立 $c[i]=\sum_{j=0}^{i-1} x[j]( 1 \leq i \leq 24)$,其中 $x[j]$是j这个时刻实际开始工作的人数。并且$c[0]=0$,且只有c[0]为已知,其他为未知。
那么我们要求解的就是c[24]的最小值。
同样我们也设立$A[i]=\sum_{j=0}^{i-1} num[j]( 1 \leq i \leq 24)$,其中 $num[j]$是j这个时刻开始工作人数的最大值。 并且$A[0]=0$。
还有$R[i]$表示i~i+1这短时间要有多少人工作。
那我们可以轻易地得出下面的不等式:
$(1\leq i \leq 8)$:
$ c[i]-c[0]+c[24]-c[16+i] \leq R[i-1] $,其中-c[0]可以去掉。
$(9\leq i \leq 24)$:
$ c[i]-c[i-8] \leq R[i-1] $
当然对于所有的$(1\leq i \leq 24)$:
$ c[i]-c[i-1] \leq x[i-1] $
$ c[i]-c[i-1] \geq 0 $
除了第一个1~8的不等式,我们都可以直接转化为最短路(最长路)用spfa求解。
对于第一个不等式 我们不能利用类似于$c[24]-c[16+i] \leq A[24]-A[16+i] $这样的不等式条件去进行加减变换,因为这会改变约束条件使得答案不正确。
同时 $c[24]-c[16+i] \leq A[24]-A[16+i] $ 已经改变了初始的约束条件。
所以我们只能去先确定其中一个未知数的值,然后spfa一遍看他符不符合这些不等式的情况,符合则该未知数的值即为该未知数的是解之一。那么我选择确定c[24],因为他正好是我们要求的答案ans。
因此我们可以二分查找最小的ans,也可以0~n枚举一遍ans,n=A[24]。
当然我们既然确定了ans,那么我们第一个不等式就变成了:
$ c[i]-c[16+i] \leq R[i-1]-ans $
还要加入约束条件
$ c[24]-c[0] \leq ans $ 这个约束条件即为ans确定的不等式表达。
 
  1 #include<cstdio>
  2 #include<iostream>
  3 #include<cstring>
  4 #include<vector>
  5 #include<queue>
  6 #define INF 1000000000
  7 #define clr(x) memset(x,0,sizeof(x))
  8 #define clr_1(x) memset(x,-1,sizeof(x))
  9 #define clrmax(x) memset(x,0x3f3f3f3f,sizeof(x))
 10 #define clrmin(x) memset(x,-0x3f3f3f3f,sizeof(x))
 11 using namespace std;
 12 struct node
 13 {
 14     int to,val,next;
 15 }edge[110*3];
 16 queue<int> Q;
 17 int head[110];
 18 int dis[110];
 19 int R[110];
 20 int in[110],inf[110];
 21 int x[110];
 22 int c[110];
 23 int n,cnt,l,r,k,ans;
 24 void addedge(int l,int r,int k);
 25 bool spfa(int s);
 26 void init();
 27 int min(int a,int b)
 28 {
 29     return a<b?a:b;
 30 }
 31 int main()
 32 {
 33     int T;
 34     scanf("%d",&T);
 35     while(T--)
 36     {
 37         clr(x);
 38         while(!Q.empty())
 39             Q.pop();
 40         for(int i=0;i<=23;i++)
 41             scanf("%d",&R[i]);
 42         scanf("%d",&n);
 43         for(int i=1;i<=n;i++)
 44         {
 45             scanf("%d",&l);
 46             x[l]++;
 47         }
 48         c[0]=0;
 49         for(int i=1;i<=24;i++)
 50         {
 51             c[i]=c[i-1]+x[i-1];
 52         }
 53         ans=-1;
 54         for(int kase=0;kase<=n;kase++)
 55         {
 56             init();
 57             for(int i=1;i<=8;i++)
 58                 addedge(16+i,i,R[i-1]-kase);
 59             for(int i=9;i<=24;i++)
 60                 addedge(i-8,i,R[i-1]);
 61             for(int i=1;i<=24;i++)
 62             {
 63                 addedge(i,i-1,-x[i-1]);
 64                 addedge(i-1,i,0);
 65             }
 66             addedge(0,24,kase);
 67             if(spfa(0))
 68             {
 69                 ans=kase;
 70                 break;
 71             }
 72         }
 73         if(ans==-1)
 74             printf("No Solution\n");
 75         else
 76             printf("%d\n",ans);
 77     }
 78     return 0;
 79 }
 80 void addedge(int l,int r,int k)
 81 {
 82     edge[++cnt].to=r;
 83     edge[cnt].val=k;
 84     edge[cnt].next=head[l];
 85     head[l]=cnt;
 86     return;
 87 }
 88 bool spfa(int s)
 89 {
 90     dis[s]=0;
 91     Q.push(s);
 92     inf[s]=1;
 93     in[s]=1;
 94     int v,k;
 95     while(!Q.empty())
 96     {
 97         v=Q.front();
 98         Q.pop();
 99         inf[v]=0;
100         k=head[v];
101         while(k!=-1)
102         {
103             if(dis[v]+edge[k].val>dis[edge[k].to])
104             {
105                 dis[edge[k].to]=dis[v]+edge[k].val;
106                 if(!inf[edge[k].to])
107                 {
108                     if(++in[edge[k].to]>24)
109                         return false;
110                     inf[edge[k].to]=1;
111                     Q.push(edge[k].to);
112                 }
113             }
114             k=edge[k].next;
115         }
116     }
117     return true;
118 }
119 void init()
120 {
121         clr(inf);
122         clr_1(head);
123         clrmin(dis);
124         clr(in);
125         cnt=0;
126         return ;
127 }

 

转载于:https://www.cnblogs.com/wujiechao/p/6581233.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值