题面
题意
一家超市24小时营业,给出24小时每小时至少需要的员工数量和n名员工的申请开工时间,每名员工连续工作8小时,问最少雇佣员工数量.
做法
利用前缀和可以发现题目可以转化为多个形如x+y<=b的不等式,因而用差分约束系统求解,s[i]表示0到i时雇佣的员工数量和,可以得到以下方程:
1.s[i]>=s[i-1],每小时雇佣的员工数量大于等于0.
2.s[i]-s[i+16]>=need[i]-n (i<8,n表示所选员工总数) , s[i]-s[i-8]>=need[i](i >=8),满足每小时需要的员工数
3.s[24]-s[0]<=n
4.s[i]-s[i-1]<=have[i]
二分答案,用这种方法判断是否可行
代码
#include<iostream>
#include<cstdio>
#include<cstring>
#include<queue>
#define INF 0x3f3f3f3f
#define N 30
#define M 100100
using namespace std;
int n,m,T,bb,need[N],have[N],first[N],l,r,mid,d[N],cur[N],bj,cnt[N];
bool in[N];
struct Bn
{
int to,next,quan;
} bn[M];
queue<int>que;
inline void add(int u,int v,int w)
{
bb++;
bn[bb].to=v;
bn[bb].quan=w;
bn[bb].next=first[u];
first[u]=bb;
}
inline bool check(int u)
{
int i,j,p,q;
bb=bj;
for(i=0;i<=24;i++)
{
first[i]=cur[i];
}
for(i=1; i<=7; i++)
{
add(i,i+16,u-need[i]);
}
add(24,0,-u);
for(; !que.empty(); que.pop());
memset(in,0,sizeof(in));
memset(d,INF,sizeof(d));
memset(cnt,0,sizeof(cnt));
que.push(24);
d[24]=u;
for(; !que.empty();)
{
q=que.front();
que.pop();
in[q]=0;
cnt[q]++;
for(p=first[q]; p!=-1; p=bn[p].next)
{
if(d[bn[p].to]>d[q]+bn[p].quan)
{
d[bn[p].to]=d[q]+bn[p].quan;
if(!in[bn[p].to])
{
in[bn[p].to]=1;
que.push(bn[p].to);
}
}
}
if(cnt[q]>25) return 0;
}
return (!d[0]);
}
int main()
{
int i,j,p,q;
cin>>T;
while(T--)
{
bb=0;
memset(have,0,sizeof(have));
memset(first,-1,sizeof(first));
for(i=1; i<=24; i++)
{
scanf("%d",&need[i]);
}
scanf("%d",&n);
for(i=1; i<=n; i++)
{
scanf("%d",&p);
have[++p]++;
}
for(i=1; i<=24; i++)
{
add(i,i-1,0);
}
for(i=8; i<=24; i++)
{
add(i,i-8,-need[i]);
}
for(i=1; i<=24; i++)
{
add(i-1,i,have[i]);
}
bj=bb;
for(i=0;i<=24;i++)
{
cur[i]=first[i];
}
l=1;
r=n;
if(!check(n))
{
puts("No Solution");
continue;
}
for(; l+1<r;)
{
mid=(l+r)>>1;
check(mid)?r=mid:l=mid;
}
if(l==r)
{
printf("%d\n",l);
continue;
}
check(l)?printf("%d\n",l):printf("%d\n",r);
}
}