标签:
转载请注明出处: http://www.cnblogs.com/fraud/ ——by fraud
题意:一商店二十四小时营业,但每个时间段需求的出纳员不同,现有n个人申请这份工作,其可以从固定时间t连续工作八个小时,问在满足需求的情况下最小需要多少个出纳
一道十分经典的差分约束题目,在构图上稍有难度
为避免负数,时间计数1~24。
令:
r[i]表示i时间需要的人数 (1<=i<=24)
num[i]表示i时间应聘的人数 (1<=i<=24)
x[i]表示i时间录用的人数 (0<=i<=24),其中令x[0]=0
再设s[i]=x[0]+x[1]+……+x[i] (0<=i<=24),
由题意,可得如下方程组:
(1) s[i]-s[i-8]>=R[i] (8<=i<=24)
(2) s[i]-s[16+i]>=R[i]-s[24] (1<=i<=7)
(3) s[i]-s[i-1]>=0 (1<=i<=24)
(4) s[i-1]-s[i]>=-T[i] (1<=i<=24)
这样就得到了四个相同形式的大于等于方程组,我们只需要枚举s[24]即可处理。可以使用二分优化。
ps:对于A-B>=C的方程,即连一条从B至A的权值为C的有向边。
1 #include <iostream> 2 #include <cstring> 3 #include <cstdio> 4 #include <queue> 5 #define REP(A,X) for(int A=0;A<X;A++) 6 using namespace std; 7 #define INF 0x7fffffff 8 #define MAXN 10010 9 struct node{ 10 int v,d,next; 11 }edge[MAXN]; 12 int head[110]; 13 int inihead[110]; 14 int e=0; 15 void init() 16 { 17 e=0; 18 REP(i,110)head[i]=-1; 19 } 20 void add_edge(int u,int v,int d) 21 { 22 edge[e].v=v; 23 edge[e].d=d; 24 edge[e].next=head[u]; 25 head[u]=e; 26 e++; 27 } 28 int dis[MAXN]; 29 int vis[MAXN]; 30 int cnt[MAXN]; 31 int r[MAXN]; 32 int num[MAXN]; 33 int spfa(int mid){ 34 REP(i,25)vis[i]=0; 35 REP(i,25)dis[i]=-INF; 36 REP(i,25)cnt[i]=0; 37 queue<int>q; 38 q.push(0); 39 vis[0]=1; 40 cnt[0]++; 41 dis[0]=0; 42 while(!q.empty()) 43 { 44 int x=q.front(); 45 q.pop(); 46 for(int i=head[x];i!=-1;i=edge[i].next) 47 { 48 int y=edge[i].v; 49 int d=edge[i].d; 50 if(dis[y]<dis[x]+d) 51 { 52 dis[y]=dis[x]+d; 53 if(!vis[y]) 54 { 55 q.push(y); 56 vis[y]=1; 57 cnt[y]++; 58 if(cnt[y]>25)return false; 59 } 60 } 61 } 62 vis[x]=0; 63 } 64 return 1; 65 66 } 67 68 int main() 69 { 70 ios::sync_with_stdio(false); 71 //freopen("in.in","r",stdin); 72 int t; 73 scanf("%d",&t); 74 while(t--) 75 { 76 REP(i,24)scanf("%d",&r[i+1]); 77 int n; 78 int a; 79 scanf("%d",&n); 80 REP(i,25)num[i+1]=0; 81 REP(i,n){ 82 scanf("%d",&a); 83 num[a+1]++; 84 } 85 init(); 86 for(int i=1;i<=24;i++){ 87 if(i>7)add_edge(i-8,i,r[i]); 88 add_edge(i,i-1,-num[i]); 89 add_edge(i-1,i,0); 90 } 91 int tempe=e; 92 REP(i,25)inihead[i]=head[i]; 93 int x=0,y=n; 94 int ans=INF; 95 while(x<y) 96 { 97 e=tempe; 98 int mid=(x+y)/2; 99 REP(i,25) head[i]=inihead[i]; 100 for(int i=1;i<8;i++) add_edge(i+16,i,r[i]-mid); 101 add_edge(0,24,mid); 102 if(spfa(mid)){ 103 y=mid; 104 ans=min(mid,ans); 105 } 106 else{ 107 x=mid+1; 108 } 109 } 110 if(ans>n)printf("No Solution\n"); 111 else printf("%d\n",ans); 112 } 113 return 0; 114 }
POJ1275/ZOJ1420/HDU1529 Cashier Employment (差分约束)
标签:
原文地址:http://www.cnblogs.com/fraud/p/4304350.html