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.
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.
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.
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小时)比如 1 0 0 0 0 。。。。也就是说在第0个小时的时候要用一个人,其他的时间都不用人,在给你一些人工作的起始时间,如果雇佣了这个人,那么这个人就会从自己的其实时间工作8个小时后离开,给你需求和可雇佣的员工,问你满足需求超时最少雇佣多少人。
经典的差分约束,之前尝试过很多次都没AC,今天终于AC了,现在我们就来找各种隐含条件。
num[i] 表示第i个小时开始的有多少个人。
r[i] 表示第i个小时最少雇佣多少人。
s[i] 表示1。。。i小时开始工作的有多少人。 (我们以S为核心建图)
第i个小时雇佣并开始工作的人数 >= 0
则 s[i] - s[i-1] >= 0
第i个小时雇佣并开始工作的人数 <= num[i]
则 s[i] - s[i-1] <= num[i] 转化成 s[i-1] - s[i] >= -num[i]
第i个小时雇佣的人数 >= r[i]
则
s[i] - s[i-8] >= r[i] (i >= 8 && i <= 24) s[24] +
s[i] - s[i + 16] >= r[i] (i <= 7)
观察最后一个不等式,出现了三个变量,不符合差分约束形式,所以我们就直接二分枚举
s[24]的值,也就是二分枚举雇佣人数的值,这样就把最后一个转换成
s[i] - s[i + 16] >= r[i] - mid
最后别忘了还有一个限制条件就是s[24] - s[0] = mid,=怎么建边呢?我们可以这样
s[24] - s[0] >= mid并且 s[24] - s[0] <= mid
第二个转换成 s[0] - s[24] >= -mid;
这样就可以二分下去了。。。
#include
#include
#include
#include
#include
#include
const int M=30+5;
const int N=10000+5;
const int INF=1000000000;
using namespace std;
typedef struct
{
int to ,cost ,next;
}STAR;
STAR E[N];
int list[M],tot,s_x[M],r[30],num[1100];
void add(int a ,int b ,int c)
{
E[++tot].to=b;
E[tot].cost=c;
E[tot].next=list[a];
list[a]=tot;
}
int Spfa(int s ,int n)
{
for (int i=0;i<=n;i++)
s_x[i]=-INF;
int mark[M]={0};
int in[M]={0};
s_x[s]=0;
mark[s]=in[s]=1;
queue<int> q;
q.push(s);
while(!q.empty())
{
int xin,tou;
tou=q.front();
q.pop();
mark[tou]=0;
for (int k=list[tou];k;k=E[k].next)
{
xin=E[k].to;
if (s_x[xin]if (!mark[xin])
{
mark[xin]=1;
if (++in[xin]>n) return 0;
q.push(xin);
}
}
}
}
return 1;
}
bool ok(int mid)
{
memset(list,0,sizeof(list));
tot=1;
for (int i=1;i<=24;i++)
{
add(i-1,i,0);
add(i,i-1,-num[i]);
if (i>=8) add(i-8,i,r[i]);
else add(i+16,i,r[i]-mid);
}
add(0,24,mid);
add(24,0,-mid);
return Spfa(0,24);
}
int main ()
{
int t,i,a,n;
scanf("%d",&t);
while(t--)
{
for (i=1;i<=24;i++)
scanf("%d",&r[i]);
scanf("%d",&n);
memset(num,0,sizeof(num));
for (i=1;i<=n;i++)
{
scanf("%d",&a);
num[a+1]++;
}
int low,mid,up;
low=0,up=n;
int ans=-1;
while(low<=up)
{
mid=(low+up)>>1;
if(ok(mid))
{
ans=mid;
up=mid-1;
}
else low=mid+1;
}
if(ans==-1) puts("No Solution");
else printf("%d\n",ans);
}
return 0;
}