题目
1∼24小时中第 i i i个小时需要 r i r_i ri个出纳员,有 n n n个人应聘,第 i i i从 x i x_i xi开始工作,一直工作8个小时。求至少要招募多少人应聘。
分析
首先 0 ≤ s i − s i − 1 ≤ n u m [ i ] 0\leq s_i-s_{i-1}\leq num[i] 0≤si−si−1≤num[i],然后 s i − s i − 8 ≥ r i s_i-s_{i-8}\geq r_i si−si−8≥ri,接着 s i − s i − 16 ≥ r i − s 24 s_i-s_{i-16}\geq r_i-s_{24} si−si−16≥ri−s24,通过这些可以建立一个最长路,但是当出现正环的时候无解,还有 s 2 4 s_24 s24需要枚举
代码
#include <cstdio>
#include <cctype>
#include <queue>
#include <cstring>
#define rr register
using namespace std;
struct node{int y,w,next;}e[101];
int k,n,ls[31],cnt[31],nee[31];
inline signed iut(){
rr int ans=0; rr char c=getchar();
while (!isdigit(c)) c=getchar();
while (isdigit(c)) ans=(ans<<3)+(ans<<1)+(c^48),c=getchar();
return ans;
}
inline void add(int x,int y,int w){
e[++k]=(node){y,w,ls[x]}; ls[x]=k;
}
inline bool spfa(int ans){
rr int dis[31],ccnt[31]; rr bool v[31];
memset(dis,0xcf,sizeof(dis));
memset(v,0,sizeof(v));
memset(ccnt,0,sizeof(ccnt));
rr queue<int>q; q.push(0);
dis[0]=0; v[0]=1;
while (q.size()){
rr int x=q.front(); q.pop();
if ((++ccnt[x])==24) return 0;
for (rr int i=ls[x];~i;i=e[i].next)
if (dis[e[i].y]<dis[x]+e[i].w){
dis[e[i].y]=dis[x]+e[i].w;
if (!v[e[i].y]){
v[e[i].y]=1;
q.push(e[i].y);
}
}
v[x]=0;
}
return dis[24]==ans;
}
signed main(){
for (rr int t=iut();t;--t){
memset(cnt,0,sizeof(cnt));
for (rr int i=1;i<25;++i) nee[i]=iut();
n=iut(); rr bool flag=0;
for (rr int i=1;i<=n;++i) ++cnt[iut()+1];
for (rr int i=0;i<=n;++i){
memset(ls,-1,sizeof(ls)); k=0;
add(0,24,i);
for (rr int j=1;j<25;++j){
add(j-1,j,0),add(j,j-1,-cnt[j]);
if (j>7) add(j-8,j,nee[j]);
else add(j+16,j,nee[j]-i);
}
if (spfa(i)){
flag=1,printf("%d",i);
break;
}
}
if (!flag) printf("No Solution");
putchar(10);
}
return 0;
}