标签:== memset 条件 问题 无法 lin customers specified 转换
Description
Input
Output
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
Solution:
这题是比较难想的(而且难调的)差分约束的题。。。
简单讲一下题意:在一家超市里,每个时刻都需要有营业员看管,R(i) (0 <= i < 24)表示从i时刻开始到i+1时刻结束需要的营业员的数目,现在有N(N <= 1000)个申请人申请这项工作,并且每个申请者都有一个起始工作时间 ti,如果第i个申请者被录用,那么他会从ti时刻开始连续工作8小时。现在要求选择一些申请者进行录用,使得任何一个时刻i,营业员数目都能大于等于R(i)。求出至少需要录用多少营业员。
我们可以转换一下思维:
首先,由于每天的工作情况都是一样的,所以我们只需要求出一天的情况即可。
再根据题意,令$s[i]$为一天内前$i+1$个小时录用的人数,分析:
1、如果$i>=7$,则$s[i] - s[i-8] \geq R[i]$;
2、如果$0 \leq i < 7$,则可以推出$s[23] - s[i+16] + s[i] \geq R[i]$;
3、同时每个时刻录用的人数有个上限,假设第$i$时刻最多可以录用的人数为$b[i]$,则对于每一个$i$有$0 \leq s[i] - s[i-1] \leq b[i]$。
现在需要解决的一个问题是,第二个不等式中包含$3$个$s$组的变量,不能去线性组合了,那么如何建图呢?
既然有三个变量,而总的答案不会太大,所以可以只需要枚举$s[23]$,那么这个量就是已知的了,因此不等式可以变为$s[i] - s[i+16]\geq R[i] - s[23]$,但是必须明白的一点是,既然$s[23]$是枚举的一天的录用人数的最小数目,我们建图之后求出的$s[23]$也应该为枚举的那个值,可以从$0$到$n$枚举$s[23]$,第一个值便是答案,但是可以更高效地求解,因为问题具有单调性,直接怼二分.
最后,因为s$[-1] = 0$,数组越界无法表示,所以需要整体向右移一位即可,那么令$s[0] = 0$。
思路就很清晰了,二分$s[24]$求满足条件的最小值,若不存在则输出无解。
代码:
1 #include<bits/stdc++.h> 2 #define il inline 3 #define For(i,a,b) for(int (i)=(a);(i)<=(b);(i)++) 4 using namespace std; 5 const int N=2005,M=26,inf=23333333; 6 int T,n,a[M],dis[M],tot[M],net[N],to[N],cnt,h[M],w[N]; 7 bool vis[M]; 8 queue<int>q; 9 10 il int gi(){ 11 int a=0;char x=getchar(); 12 while(x<‘0‘||x>‘9‘)x=getchar(); 13 while(x>=‘0‘&&x<=‘9‘)a=(a<<3)+(a<<1)+x-48,x=getchar(); 14 return a; 15 } 16 17 il void add(int u,int v,int c){to[++cnt]=v,net[cnt]=h[u],h[u]=cnt,w[cnt]=c;} 18 19 il void init(int x){ 20 cnt=0; 21 memset(vis,0,sizeof(vis)); 22 memset(h,0,sizeof(h)); 23 memset(dis,-0x3f,sizeof(dis)); 24 while(!q.empty())q.pop(); 25 For(i,0,23) add(i,i+1,0),add(i+1,i,-tot[i]); 26 For(i,7,23) add(i-7,i+1,a[i]); 27 add(0,24,x),add(24,0,-x); 28 For(i,0,6) add(i+17,i+1,a[i]-x); 29 } 30 31 il bool check(int x){ 32 init(x); 33 q.push(0);dis[0]=0; 34 while(!q.empty()){ 35 int u=q.front();q.pop();vis[u]=0; 36 if(u==24&&dis[u]>x)return 0; 37 for(int i=h[u];i;i=net[i]) 38 if(dis[to[i]]<dis[u]+w[i]){ 39 dis[to[i]]=dis[u]+w[i]; 40 if(!vis[to[i]])q.push(to[i]),vis[to[i]]=1; 41 } 42 } 43 return dis[24]==x?1:0; 44 } 45 46 il void solve(){ 47 int l=0,r=n+1,mid,ans=inf; 48 while(l<=r){ 49 mid=l+r>>1; 50 if(check(mid))r=mid-1,ans=mid; 51 else l=mid+1; 52 } 53 if(ans>n)printf("No Solution\n"); 54 else printf("%d\n",ans); 55 } 56 57 int main(){ 58 T=gi(); 59 while(T--){ 60 memset(tot,0,sizeof(tot)); 61 For(i,0,23) a[i]=gi(); 62 n=gi(); 63 int u; 64 For(i,1,n)u=gi(),tot[u]++; 65 solve(); 66 } 67 return 0; 68 }
标签:== memset 条件 问题 无法 lin customers specified 转换
原文地址:https://www.cnblogs.com/five20/p/9174887.html