(1)题意:
超市要招员工,需要保证每个时间段内都有xi个员工,问至少需要多少个员工。
第一行输入T表示测试数据的组数
第二行24个数,R[i]表示第i小时到第i+1小时内,至少需要几个员工;
之后一个n,表示总共招工的人数;
然后n行,每行一个x表示这个人的工作起始时间ti,他从ti开始工作,工作8个小时。
(2)思路:
先找到人数与工作时间的关系,因为每天都是循环的所以只考虑一天的情况即可。
设s[i]数组表示从这一天的0点开始到第i+1个小时期间至少需要多少个人。
统计每个小时的开始工作的人数tim[i],
然后对每一天的每个小时都有0<=s[i]-s[i-1]<=tim[i];------------(1)
然后考虑需求的限制人数:
如果0<=i<7 s[i]-s[i-8]>=R[i];---------------(2)
如果i>=7 (s[23]-s[i+16]) + s[i]>=R[i];-------------(3)
将(3)式改一下,s[i] - s[i+16]>=R[i] - s[23];
可以发现s[23]是一个定值,所以可以确定s[23]的值,然后二分求解。
因为i-8小于0,所以将所有的i改为i+1,初始化s[0] = 0.
(3)代码:
#include<iostream>
#include<cstdio>
#include<cstring>
#include<vector>
#include<queue>
#include<algorithm>
using namespace std;
const int maxn = 1024;
const int INF = 1e9+10;
int vis[maxn],dis[maxn],head[maxn],tot,R[50],tim[50];
struct Node{
int v,nxt,w;
}cur[maxn<<2];
void Init(){
memset(head,-1,sizeof(head));
tot = 0;
}
void Add(int x,int y,int z){
cur[tot] = Node{y,head[x],z};
head[x] = tot++;
}
bool spfa(int w){
for(int i=0;i<=24;i++){
dis[i] = -INF;vis[i] = 0;
}
queue <int> q;
q.push(0);dis[0] = 0;
while(!q.empty()){
int x = q.front();q.pop();vis[x] = 0;
if(x==24&&dis[x]>w) return false;
for(int i=head[x];i!=-1;i=cur[i].nxt){
int y = cur[i].v;
if(dis[y]<dis[x]+cur[i].w){
dis[y] = dis[x]+cur[i].w;
if(vis[y]==0){
vis[y] = 1;
q.push(y);
}
}
}
}
return dis[24]<=w;
}
int main(void){
int T;scanf("%d",&T);
while(T--){
int n;
for(int i=0;i<=23;i++) scanf("%d",&R[i]);
memset(tim,0,sizeof(tim));
scanf("%d",&n);
for(int i=0;i<n;i++){
int x;scanf("%d",&x);tim[x]++;
}
int l = 0,r = n+1,ans = n+1;
while(l<=r){
int mid = (l+r)>>1;
Init();
for(int i=0;i<=23;i++){
Add(i,i+1,0);
Add(i+1,i,-tim[i]);
}
for(int i=7;i<=23;i++){
Add(i-7,i+1,R[i]);
}
Add(0,24,mid);Add(24,0,-mid);
for(int i=0;i<7;i++){
Add(i+17,i+1,R[i]-mid);
}
if(spfa(mid)==true){
ans = mid;r = mid-1;
}
else l = mid+1;
}
if(ans>n) printf("No Solution\n");
else printf("%d\n",ans);
}
return 0;
}