HDU1529 Cashier Employment【差分约束+SPFA+二分】

C a s h i e r   E m p l o y m e n t Cashier\ Employment

Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 65536/32768 K (Java/Others)
Total Submission(s): 1748 Accepted Submission(s): 797

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.

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

Source
Asia 2000, Tehran (Iran)

题目大意:

超市要雇佣一些出纳员,给出0~24小时各个时刻需要的出纳员数,R[0],R[1]…R[23]。
R[0]表示从午夜到上午1:00需要的出纳员数量。然后给出n个申请者,每个申请者从一个特定的时间t开始,连续工作八个小时(如果超过了23:00则可以补到下一天),要求计算出满足上述限制的雇佣出纳员的最少数量。

分析:

给出了一些限制条件,可以得到一些不等式模型:
(为了方便后续计算,把时间从0~23改成1~24)
令num[i]为i时刻能够雇佣的总人数
s[i]为从s[0]到s[i]雇佣人数的总数
need[i]表示i时刻需要的最少雇员数
s[i]-s[i-1]表示i时刻雇用到的实际人数
i时刻能雇到的人数肯定不会超过应聘该时刻的总人数:0<=s[i]-s[i-1]<=num[i],1<=i<=24
i时刻正在工作的人数肯定不会少于i时刻需要的人数:(此时分两种情况讨论)
①s[i]-s[i-8]>=need[i],8 <= i <= 24
②s[i]+s[24]-s[i+16]>=need[i],1 <= i < 8

将上述不等式化成差分约束的标准形式:
①s[i]-s[i-1]>=0 ,1<=i<=24
②s[i-1]-s[i]>=-num[i],1<=i<=24
③s[i]-s[i-8]>=need[i],8<=i<=24
④s[i]-s[i+16]>=need[i]-s[24],1<=i<8

其中need[i]和num[i]都是已知的,所以可以根据前三式直接建图,而④中出现了s[24],而s[24]就是要求的答案,所以对此我们可以用二分来查找s[24]所有可能的值,然后取最小的那个就是答案。

对于建图:X[ i ] - X[ j ] >= C表示从j向i建一条权值为C的边 建图完成之后用SPFA跑一遍最长路径就行了

弱弱的代码:

#include<cstdio>
#include<cstring>
#include<algorithm>
#include<queue>
#include<vector>
using namespace std;
const int maxn = 30;
const int INF = 0x3f3f3f3f;
int T,n;
int num[maxn],need[maxn];
struct EDGE{
	int to,cost;
};
vector<EDGE> G[maxn];
void add_edge(int u,int v,int c){
	G[u].push_back((EDGE){v,c});
}
void input(){
	memset(num,0,sizeof(num));
	for(int i=1;i<=24;i++) scanf("%d",&need[i]);
	scanf("%d",&n);
	for(int i=1;i<=n;i++){
		int t;
		scanf("%d",&t);
		num[t+1]++;
	}
}
void build(int m){
	for(int i=0;i<maxn;i++) G[i].clear();
	//for(int i=1;i<=24;i++) add_edge(i-1,i,0);
	for(int i=1;i<=24;i++) add_edge(i,i-1,-num[i]);
	for(int i=8;i<=24;i++) add_edge(i-8,i,need[i]);
	for(int i=1;i<8;i++) add_edge(i+16,i,need[i]-m);
	add_edge(0,24,m);
}
bool SPFA(int m){
	build(m);
	int vis[maxn],inqueue[maxn],dist[maxn];
	memset(vis,0,sizeof(vis));
	memset(inqueue,0,sizeof(inqueue));
	memset(dist,-INF,sizeof(dist));
	//fill(dist,dist+maxn,-INF);
	vis[0] = 1;inqueue[0]++;dist[0] = 0;
	queue<int> que;
	que.push(0);
	while(!que.empty()){
		int now = que.front();
		que.pop();vis[now] = 0;
		for(int i=0;i<G[now].size();i++){
			EDGE e = G[now][i];
			if(e.cost+dist[now]>dist[e.to]){
				dist[e.to] = e.cost + dist[now];
				if(!vis[e.to]){
					if(++inqueue[e.to]>24) return false;
					vis[e.to] = 1;
					que.push(e.to);
				}
			}
		}
	}
	return true;
}
int main(){
	scanf("%d",&T);
	while(T--){
		input();
		int ans = -1;
		int l=0,r=n,mid;
		while(l<=r){
			mid = (l+r)>>1;
			if(SPFA(mid)){
				ans = mid;
				r = mid-1;
			}
			else l = mid+1;
		}
		if(ans==-1) printf("No Solution\n");
		else printf("%d\n",ans);
	}
	return 0;
}

猜你喜欢

转载自blog.csdn.net/qq_43710979/article/details/89643590