AcWing 393. 雇佣收银员

题目大意
一个超市需要收银员,各个时间段需要的最小数量为r[i],有n个人申请岗位,开始工作的时间为t[i],问最少需要多少收银员?
解题思路
可以考虑差分约束,
数组r[i]表示超市在i-1时到i时需要的收银员数量;
num[i]表示i-1~i时可以工作的收银员数量
s[i]表示i-1~i时开始工作的收银员人数
sum[i]表示0~i时所用的收银员人数(即s[]的前缀和数组)
对于i 满足1<=i<=24;
1) num[i]>=sum[i]-sum[i-1]>=0
含义为:第i时的收银员人数满足小于等于num[i],且大于等于0
可变形为:
sum[i]>=sum[i-1]+0
即i-1 -->i 边权w=0
sum[i-1]>=sum[i]-num[i]
即i -->i-1 边权w=-num[i]
2)s[i]+s[i-1]+s[i-2]+s[i-3]+s[i-4]+s[i-5]+s[i-6]+s[i-7]>=r[i]
含义为:在第i时工作的收银员人数要大于实际需要的收银员人数
解释:因为每个人要工作8小时,所以第i时的工作人数要算上距今八个小时内开始工作的收银员人数。
可以变形为sum[i]-sum[i-8]>=r[i]
sum[i]>=sum[i-8]+r[i]
即i-8-->i 边权w=r[i]
对于此式 i的范围为[8,24]
3) sum[24]-sum[i+16]+sum[i]>=r[i]
含义为:从i时到前一天的i+16时开始工作的人数大于i时所需要的人数,即在第i时工作的收银员人数要大于实际需要的收银员人数。与2)不同点在于此式子适用于跨天工作
可变形为 sum[i]>=sum[i+16]+r[i]-sum[24]
即 i+16-->i 边权w=r[i]-sum[24]
对于此式 i的范围为[1,7]
4) sum[24]==c
等价于sum[24]>=c && sum[24]<=c
可以转化为sum[24]>=sum[0]+c && sum[0]>=sum[24]-c
即 0-->24 w=c && 24-->0 w=-c
代码
点击查看代码
#include<bits/stdc++.h>
using namespace std;
const int N=50,M=510,K=1010;
struct node{
int from,to,next,d;
}f[M];int h[N],idx=0;
void add(int from,int to,int d)
{
f[idx]={from,to,h[from],d};
h[from]=idx;idx++;
}
int T,r[N],num[N],n;
int dist[N],cnt[N],v[N];
void build(int c)
{
memset(dist,0xcf,sizeof dist);
memset(v,0,sizeof v);
memset(cnt,0,sizeof cnt);
memset(h,-1,sizeof h);
idx=0;
add(0,24,c);add(24,0,-c);
for(int i=1;i<=24;i++)
{add(i-1,i,0);add(i,i-1,-num[i]);}
for(int i=8;i<=24;i++) add(i-8,i,r[i]);
for(int i=1;i<=7;i++) add(i+16,i,r[i]-c);
return ;
}
bool spfa(int c)
{
build(c);
queue<int> q;
q.push(0);v[0]=true;dist[0]=0;
while(q.size())
{
int t=q.front();
q.pop();
v[t]=false;
for(int i=h[t];~i;i=f[i].next )
{
int ver=f[i].to;
if(dist[ver]<dist[t]+f[i].d)
{
dist[ver]=dist[t]+f[i].d;
cnt[ver]=cnt[t]+1;
if(cnt[ver]>=25) return false;
if(!v[ver]) q.push(ver);
}
}
}
return true;
}
int main()
{
scanf("%d",&T);
while(T--)
{
for(int i=1;i<=24;i++)
scanf("%d",&r[i]);
scanf("%d",&n);
memset(num,0,sizeof num);
for(int i=1;i<=n;i++)
{
int t;
scanf("%d",&t);
num[t+1]++;
}
bool success=false;
for(int i=1;i<=1010;i++)
{
if(spfa(i))
{
cout<<i<<endl;
success=true;
break;
}
}
if(success==false) printf("No Solution\n");
}
return 0;
}

浙公网安备 33010602011771号