正题
题目链接:http://poj.org/problem?id=1275
题目大意
1∼241\sim 241∼24小时中第iii个小时需要rir_iri个出纳员
有nnn个人应聘,第iii从xix_ixi开始工作,一直工作8个小时。
求至少要招募多少人应聘。
解题思路
numinum_inumi表示第iii个小时有多少人招聘。
设定kik_iki表示第iii个小时放多少人
这时需要ki≥rIk_i\geq r_Iki≥rI且∑i=07num(n−i+24)%24+1≤ki\sum_{i=0}^7num_{(n-i+24)\%24+1}\leq k_i∑i=07num(n−i+24)%24+1≤ki
这时我们要设定差分约束si=∑i=1isis_i=\sum_{i=1}^is_isi=∑i=1isi
然后得出
si−si−1≥0s_i-s_{i-1}\geq 0si−si−1≥0
si−1−si≥−numis_{i-1}-s_i\geq -num_isi−1−si≥−numi
si−si−8≥ris_i-s_{i-8}\geq r_isi−si−8≥ri
si−si+16≥ri−s24s_i-s_{i+16}\geq r_i-s_{24}si−si+16≥ri−s24
然后因为最后一个式子有三个未知量,所以我们枚举s24s_{24}s24就好了
codecodecode
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<queue>
using namespace std;
const int N=30;
struct edge{int to,next,w;
}a[N*8];
queue<int> q;
int T,n,tot;
int r[N],f[N],cnt[N],num[N],ls[N];
bool v[N],flag;
void addl(int x,int y,int w)
{a[++tot].to=y;a[tot].w=w;a[tot].next=ls[x];ls[x]=tot;
}
void build(int x)
{tot=0;memset(ls,0,sizeof(ls));addl(0,24,x);for(int i=1;i<=24;i++){addl(i-1,i,0);addl(i,i-1,-num[i]);if(i>=8) addl(i-8,i,r[i]);else addl(i+16,i,r[i]-x);}
}
int spfa(int ans)
{memset(f,0xcf,sizeof(f));memset(cnt,0,sizeof(cnt));memset(v,0,sizeof(v));while(!q.empty()) q.pop();q.push(0);f[0]=0;v[0]=1;while(!q.empty()){int x=q.front();v[x]=0;q.pop();for(int i=ls[x];i;i=a[i].next){int y=a[i].to;if(f[x]+a[i].w>f[y]){f[y]=f[x]+a[i].w;if(!v[y]){q.push(y);v[y]=1;}if(++cnt[y]>24)return 0;}}}if(f[24]==ans) return 1;return 0;
}
int main()
{scanf("%d",&T);while(T--){memset(num,0,sizeof(num));for(int i=1;i<=24;i++)scanf("%d",&r[i]);scanf("%d",&n);for(int i=1;i<=n;i++){int x;scanf("%d",&x);num[x+1]++;}flag=0;for(int i=0;i<=n;i++){build(i);if(spfa(i)){flag=true;printf("%d",i);break;}}if(!flag) printf("No Solution");putchar('\n');}
}