小胖超市
描述:
xuzhenyi的一家每天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
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
1
来源
huyichen
/*
约分差束--最小值--最长路
注意判断负环回路
算法分析:
设num[i] 为来应聘的在第i个小时开始工作的人数
r[i] 为第i个小时至少需要的人数
x[i] 为招到的在第i个小时开始工作的人数
根据题意有:
0 <= x[i] <= num[i]
x[i] + x[i-1] + …+ x[i-7] >= r[i] (题目中的连续工作8小时)
再设 s[i] = x[1] + … + x[i]
则有: s[i] – s[i-1] >= 0
s[i-1] – s[i] >= –num[i]
s[i] – s[i-8] >= r[i], 8 <= i <= 24
s[i] – s[i+16] >= r[i] – s[24], 1<= i <= 7
还需要添加一个隐藏不等式: s[24] – s[0] >= ans(枚举的答案)
通过枚举s[24],来检测是否满足条件,题目是求最小值,即求最长路,以0为源点。
*/
#include<iostream>
#include<cstring>
#include<queue>
#include<cstdio>
#include<cstdlib>
using namespace std;
#define maxn 1200
#define INF 0x7fffffff
struct Edge{ int to,w,next; }e[maxn];
int head[maxn],dis[maxn],tot;
int r[maxn],num[maxn],n,cnt[maxn];
bool exist[maxn];
void Add_Edge(int u,int v,int w){
e[tot].to=v;e[tot].w=w;
e[tot].next=head[u];head[u]=tot++;
}
void Built(int ans){
tot=0;
memset(head,-1,sizeof head );
Add_Edge(0,24,ans);
for(int i=1;i<=24;i++){
Add_Edge(i-1,i,0);
Add_Edge(i,i-1,-num[i]);
}
for(int i=1;i<=8;i++)
Add_Edge(i+16,i,r[i]-ans);
for(int i=9;i<=24;i++)
Add_Edge(i-8,i,r[i]);
return ;
}
queue<int> q;
bool SPFA(int ans){
while(!q.empty()) q.pop();
for(int i=1;i<=24;i++){
dis[i]=-INF;
cnt[i]=0;
exist[i]=false;
}
q.push(0);exist[0]=true;dis[0]=0;
while(!q.empty()){
int u=q.front();q.pop();exist[u]=false;
for(int i=head[u];i!=-1;i=e[i].next){
int v=e[i].to,w=e[i].w;
if(dis[v]<dis[u]+w){
dis[v]=dis[u]+w;
if(!exist[v]){
exist[v]=true;
q.push(v);
}
cnt[v]++;
if(cnt[v]>24) return 0;
}
}
}
if(dis[24]==ans) return 1;
else return 0;
}
int main(){
int Test;cin>>Test;
while(Test--){
bool flag=false;
for(int i=1;i<=24;i++){
scanf("%d",&r[i]);//r[i]表示第i时刻需要
//多少人提供服务,但是要注意r[i]实际表示i-1
//时刻的数据
num[i]=0;
}
scanf("%d",&n);
for(int t,i=1;i<=n;i++){
scanf("%d",&t);
num[t+1]++;
}
for(int i=1;i<=n;i++){
Built(i);
if(SPFA(i)==1){
flag=true;
printf("%d\n",i);
break;
}
}
if(flag==false){
printf("No Solution\n");
}
}
return 0;
}