POJ1275出纳员的雇佣【差分约束】

出纳员的雇佣

Tehran的一家每天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)更多的出纳员在工作。

输入格式:

输入文件的第一行为测试点个数(<= 20)。每组测试数据的第一行为24个整数表示R(0),R(1),..., R(23)(R(I)<= 1000)。接下来一行是N,表示申请者数目(0 <= N <= 1000),接下来每行包含一个整数tI (0 <= tI <= 23)。两组测试数据之间没有空行。

输出格式:

对于每个测试点,输出只有一行,包含一个整数,表示需要出纳员的最少数目。如果无解,你应当输出“No Solution!”

样例输入:

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

样例输出:

1

时间限制:

1s

(先每个时间段加一以便C++操作)

差分约束:

0 <= S[i]-S[i-1]<=W[i];      // 雇佣的人数少于申请者但不能为负数
S[i]-S[i-8]>=R[i]               // 当i>=8时,该方程成立,否则将出现负数显然不成立
S[i+16]-S[i]<=x-R[i]   // 当i<8时,由于昨天的雇人可以通宵上班,因此这个约束通过反面处理
S[24] - S[0] >=x                     // 最后24小时内雇佣人应该大于等于x个人

S[i]-S[j]<=K 则从顶点j向i引一条权值为K的边。该系统是否成立也就在于是否存在负环,于是用SPFA判断负环。

然而x(也就是答案)未知,而x<=1000,所以可以二分查找找出最小的x。注意归零。

 1 #include<cstdio>
 2 #include<iostream>
 3 #include<cstring>
 4 #include<queue>
 5 using namespace std;
 6 queue<int> Q;
 7 const int N=25;
 8 int R[N],W[N],dis[N],map[N][N],times[N];
 9 bool go[N][N],in[N];
10 bool SPFA(int x)
11 {
12     int tmp;
13     memset(dis,127,sizeof(dis));
14     memset(times,0,sizeof(times));
15     memset(map,0,sizeof(map));
16     memset(in,0,sizeof(in));
17     dis[24]=0;
18     times[24]=1;
19     for(int i=8;i<=24;i++) map[i][i-8]=-R[i];
20     for(int i=1;i<=7;i++) map[i][i+16]=x-R[i];
21     for(int i=1;i<=24;i++) map[i-1][i]=W[i];
22     map[24][0]=-x;
23     Q.push(24);
24     while(!Q.empty())
25     {
26         tmp=Q.front();
27         in[tmp]=0;
28         Q.pop();
29         for(int i=0;i<=24;i++) if(go[tmp][i]&&dis[i]>dis[tmp]+map[tmp][i])
30         {
31             dis[i]=dis[tmp]+map[tmp][i];
32             times[i]++;
33             if(!in[i])
34             {
35                 in[i]=1;
36                 Q.push(i);
37             }
38             if(times[i]>25) return false;
39         }
40     }
41     return (dis[0]==-x);
42 }
43 int main()
44 {
45     int lower,upper,t,n,x,mid;
46     bool flag;
47     for(int i=8;i<=24;i++) go[i][i-8]=1;
48     for(int i=1;i<=7;i++) go[i][i+16]=1;
49     for(int i=1;i<=24;i++) go[i][i-1]=go[i-1][i]=1;
50     go[24][0]=1;
51     scanf("%d",&t);
52     for(int z=1;z<=t;z++)
53     {
54         memset(W,0,sizeof(W));
55         for(int i=1;i<=24;i++) scanf("%d",&R[i]);
56         scanf("%d",&n);
57         for(int i=1;i<=n;i++)
58         {
59             scanf("%d",&x);
60             W[x+1]++;
61         }
62         lower=1;
63         upper=n;
64         flag=false;
65         while(lower<=upper)
66         {
67             mid=(lower+upper)>>1;
68             if(SPFA(mid))
69             {
70                 flag=true;
71                 upper=mid-1;
72             }
73             else lower=mid+1;
74         }
75         if(!flag) printf("No Solution\n");
76         else printf("%d\n",lower);
77     }
78 }
时间: 2024-08-02 11:04:22

POJ1275出纳员的雇佣【差分约束】的相关文章

POJ1275 Cashier Employment 【二分 + 差分约束】

题目链接 POJ1275 题解 显然可以差分约束 我们记\(W[i]\)为\(i\)时刻可以开始工作的人数 令\(s[i]\)为前\(i\)个时刻开始工作的人数的前缀和 每个时刻的要求\(r[i]\),可以通过如下限制满足: \[s[i] - s[i - 8] \ge r[i]\] \[0 \le s[i] - s[i - 1] \le W[i]\] 但是\(i - 8\)可能为负,回到上一天的时刻,导致区间不连续,不好处理 我们可以二分答案\(sum\) 将\(i < 8\)的部分改为: \[

POJ1275/ZOJ1420/HDU1529 Cashier Employment (差分约束)

转载请注明出处: 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时间

poj1275--Cashier Employment(差分约束)

poj1275:题目链接 题目大意:给出24个数,第i个数表示在(i,i+1)小时内需要的人数,之后m个数,代表m个人前来应聘,其中每个人工作连续的8小时,给出应聘的人开始工作的时间,问最少需要雇佣的人数(可以在某个时间段中人数多于需要的人数) 差分约束: 1.题目需要求什么,就找什么之间的关系(二项式),比如,题目求雇佣的人数,就找出雇佣人数之间的关系,s[i]代表从0到i一共雇佣的人数 2.注意0的问题,和总和的问题. 3.判断的问题,不能存在环,和不能违背要求的值 又因为题中雇佣人数会形成

差分约束小结

ZOJ 2770 Burn the Linked Camp /* ZOJ 2770 Burn the Linked Camp 差分约束 */ #include <iostream> #include <cstring> #include <cstdio> #include <queue> using namespace std; const int MAXN = 1009; struct Edge { int v, ne, c; } G[MAXN*MAXN]

浅谈差分约束问题

差分约束 差分约束是解决这样一类问题 给出\(n\)个形如\(x[j]-x[i]<=k\)的式子,求\(x[n]-x[1]\)的最大/最小值 思路 其实这个问题是挺套路的 我们把给出的式子变一下 \(x[j]-x[i]<=k\) \(x[j]<=x[i]+k\) 我们不难联想到图论中最短路的性质 假设\(d[x]\)表示\(1\)到\(x\)的最短路 那么对于任意一条边\((u,v)\) 有\(d[v]<=d[u]+k\)(k表示边权) 可能有些抽象,举个例子 经过计算不难得到三个

差分约束

1.bzoj3436 思路: 差分约束根据限制条件建图,注意要有一个超级源点向所有点连一条边权为0的边建图看代码. 然后spfa判负环,写bfs会超时的......实测n遍. #include<iostream> #include<cstdio> #include<algorithm> #include<cstring> #define inf 0x7fffffff #define ll long long #define N 100007 using na

bzoj2788 festival 差分约束

填坑中--链接:http://www.lydsy.com/JudgeOnline/problem.php?id=2788 题意: 有$n$个正整数$X1,X2,...,Xn$,再给出$m1+m2$个限制条件,限制分为两类:1. 给出$a,b(1<=a,b<=n)$,要求满足$Xa + 1 = Xb$2. 给出$c,d (1<=c,d<=n)$,要求满足$Xc <= Xd$在满足所有限制的条件下,求集合${Xi}$大小的最大值. 首先看情况我们也知道是差分约束-- 但是这个差分

POJ 1201 Intervals 差分约束

http://poj.org/problem?id=1201 TLE了很久,因为用了cin..... 思路和其他差分约束差不多,http://www.cppblog.com/menjitianya/archive/2015/11/19/212292.html 如果区间[a, b]中至少有c个元素,如果用上面的博客,那么说明xa - xb >= c,但是注意这里是闭区间,xa - xb是不包括b这个点的, 就比如用了[a, b]有c个元素,[b, d]有x个,那么ans = c + x - 1个,

【bzoj2330】: [SCOI2011]糖果 图论-差分约束-SPFA

[bzoj2330]: [SCOI2011]糖果 恩..就是裸的差分约束.. x=1 -> (A,B,0) (B,A,0) x=2 -> (A,B,1)  [这个情况加个A==B无解的要特判] x=3 -> (B,A,0)  [恩这个是不少于一开始zz建反了] x=4 -> (B,A,1) x=5 -> (A,B,0) 然后源点到所有点建1的边[恩据说有条链所以要反着连]跑最长路就好了 1 /* http://www.cnblogs.com/karl07/ */ 2 #inc