Cashier Employment HDU - 1529 (带未知数的差分约束)

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

题意:

有一家店,其每个小时都至少要有R(i)个人在工作。有N个应聘者,他们分别可以从ti时刻开始工作,且一旦开始工作就会工作8小时再停止。问最少需要雇佣多少员工

我们设截止至i点参与过工作的员工总数为ai,总人数设为x,每个点可以进行工作的人数设做num(i),根据题目条件我们可以列出不等式

i在1-7点:x-a(i+16)+a[i]>=R(i)(1到7点还有昨天一直工作到今天的员工)

i在8到24时a(i)-a(i-8)>=R(i)(当前的工作的总人数,加上八个小时前工作的总人数,就是现在在工作的人的总人数)

全天num[i]>=a[i]-a[i-1]>=0

a[24]-a[0]>=x

因为求人数的最小值x>=?,就是相应地求数值之间得最长路所以把符号都换成大于号。

最后需要加的边就是

addedge(0,24,x);

for(int i=1;i<=24;i++) { addedge(i-1 , i ,0); addedge(i , i-1 ,-num[i]); }

for(int i=1;i<8;i++) addedge(i+16,i,val[i]-x);

for(int i=8;i<=24;i++) addedge(i-8,i,val[i]);

最后来枚举x,当x恰好是最长路的值时就返回true

枚举是否需要使用二分?

答:由于SPFA的复杂度为O(K*73)(K通常为1~2)乘上最多一千个员工再乘上最大执行20次。。。撑死也就10的6次方,就不需要再用二分了。

代码:

#include<algorithm>
#include<iostream>
#include<cstring>
#include<string>
#include<cstdio>
#include<vector>
#include<stack>
#include<cmath>
#include<queue>
#include<set>
#include<map>
#define endl '\n'
#define sc(x) scanf("%d",&x)

using namespace std;
const int inf=0x3f3f3f3f;
struct Edge{
	int u,v,w;
	Edge(int u,int v,int w):u(u),v(v),w(w){} 
};
vector<Edge> edge;
vector<int> No[25];
int dis[25],vis[25];
int cnt[25];
int val[25];
int num[25];
int n,m;
void addedge(int u,int v,int w)
{
	edge.push_back(Edge(u,v,w));
	No[u].push_back(edge.size()-1);
}
void init(int x)
{
	for(int i=0;i<25;i++) No[i].clear();
	edge.clear();
	memset(vis,0,sizeof(vis));
	memset(cnt,0,sizeof(cnt));
	fill(dis,dis+25,-inf);
	addedge(0,24,x);
	for(int i=1;i<=24;i++)
	{
		addedge(i-1,i,0);
		addedge(i,i-1,-num[i]);
	}
	for(int i=1;i<8;i++) 	addedge(i+16,i,val[i]-x);
	for(int i=8;i<=24;i++)  addedge(i-8,i,val[i]);
}

int spfa(int num)
{
	//vis[0]=1;
	dis[0]=0;
	queue<int> q;
	q.push(0);
	while(!q.empty())
	{
		int S=q.front();
		q.pop();
		vis[S]=0;
		for(int i=0;i<No[S].size();i++)
		{
			int id=No[S][i];
			if(dis[edge[id].v]<dis[edge[id].u]+edge[id].w)
			{
				dis[edge[id].v]=dis[edge[id].u]+edge[id].w;
				if(!vis[edge[id].v])
				{
					vis[edge[id].v]=1;
					q.push(edge[id].v);
					if(++cnt[edge[id].v]>25) return 0;
				}
			}
		}
	}
	if(dis[24]==num)return 1;
	else return 0;
} 
int32_t main()
{
	int t;
	cin>>t;
	while(t--)
	{
		memset(num,0,sizeof(num));
		for(int i=1;i<=24;i++) sc(val[i]);
		int n;
		cin>>n;
		for(int i=0;i<n;i++) 
		{
			int T;
			sc(T);
			num[T+1]++;
		}
		int flag=0;
		for(int i=0;i<=n;i++)
		{
			init(i);
			if(spfa(i))
			{
				cout<<i<<endl;
				flag=1;
				break;
			}
			//cout<<dis[24]<<endl;
		}
		if(!flag)printf("No Solution\n");
	}
	return 0;
}

 

posted @ 2018-08-09 21:58  Fly_White  阅读(140)  评论(0编辑  收藏  举报