差分约束系统,出纳员的雇佣

来源:互联网 发布:棋牌刷分软件 编辑:程序博客网 时间:2024/05/19 19:40

Tehran的一家每天24小时营业的超市,需要一批出纳员来满足它的需要。超市经理雇佣你来帮他解决问题:超市在每天的不同时段需要不同数目的出纳员(例如:午夜时只需一小批,而下午则需要很多)来为顾客提供优质服务。他希望雇佣最少数目的出纳员。
经理已经提供你一天的每一小时需要出纳员的最少数量——R(0), R(1), …, R(23)。R(0)表示从午夜到上午1:00需要出纳员的最少数目,R(1)表示上午1:00到2:00之间需要的,等等。每一天,这些数据都是相同的。有N人申请这项工作,每个申请者I在24小时中,从一个特定的时刻开始连续工作恰好8小时,定义tI (0 <= tI <= 23)为上面提到的开始时刻。也就是说,如果第I个申请者被录取,他(她)将从tI 时刻开始连续工作8小时。
你将编写一个程序,输入R(I)(I = 0..23)和tI (I = 1..N),它们都是非负整数,计算为满足上述限制需要雇佣的最少出纳员数目。在每一时刻可以有比对应的R(I)更多的出纳员在工作。

输入格式:
输入文件的第一行为测试点个数(<= 20)。每组测试数据的第一行为24个整数表示R(0),R(1),…, R(23)(R(I)<= 1000)。接下来一行是N,表示申请者数目(0 <= N <= 1000),接下来每行包含一个整数tI (0 <= tI <= 23)。两组测试数据之间没有空行。
输出格式:
对于每个测试点,输出只有一行,包含一个整数,表示需要出纳员的最少数目。如果无解,你应当输出“No Solution!”
样例输入:
1
1 0 1 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1
5
0
23
22
1
10
样例输出:
1
时间限制:
1s
空间限制:
512M

#include<bits/stdc++.h>using namespace std;int t[30],sum,r[30],vis[30];int dis[30];int ne[101],fir[101],val[101],to[101];bool inq[101];int n,m,AwD,cnt,tot;void init(){    n=m=cnt=0;    for(int i=0;i<=25;i++)  dis[i]=2e9;    for(int i=0;i<=25;i++) r[i]=0;    for(int i=0;i<=25;i++) t[i]=0;    tot=0;}void add(int u,int v,int w){    ne[++cnt]=fir[u];fir[u]=cnt;val[cnt]=w;to[cnt]=v;}void set_up_picture(){    //人数不能为负!!!//  add(1,25,sum);    cnt=0;    for(int i=0;i<=25;i++) fir[i]=0;    for(int i=0;i<=25;i++) ne[i]=0;    for(int i=0;i<=25;i++) val[i]=0;    for(int i=0;i<=25;i++) to[i]=0;    add(24,0,-sum);    for(int i=0;i<=23;i++) add(i+1,i,0);    for(int i=0;i<=23;i++) add(i,i+1,t[i]);    for(int i=8;i<=24;i++) add(i,i-8,-r[i]);    for(int i=1;i<=7;i++) add(i,i+16,sum-r[i]);}queue <int> q;bool SPFA(){    set_up_picture();    for(int i=0;i<=25;i++) dis[i]=2e9;    for(int i=0;i<=25;i++) inq[i]=0;    for(int i=0;i<=25;i++) vis[i]=0;    while(!q.empty()) q.pop();    int i=24;    {        inq[i]=1;dis[i]=0;vis[i]++;q.push(i);    }    while(!q.empty())    {        int index=q.front();inq[index]=0;        q.pop();        for(int i=fir[index];i;i=ne[i])        {            int v=to[i];            if(dis[v]>dis[index]+val[i])            {                dis[v]=dis[index]+val[i];                if(!inq[v])                {                    inq[v]=1;vis[v]++;q.push(v);if(vis[v]>25) return 0;                }            }        }    }    return dis[0]==-sum;//我们先令最后减最前大于等于sum,最后判他用sum够不够完成该任务。}int main(){    cin>>AwD;    while(AwD--)    {        init();        for(int i=1;i<=24;i++) scanf("%d",&r[i]);        scanf("%d",&n);        for(int i=1;i<=n;i++) {scanf("%d",&m);t[m+1]++;tot++;}        bool flag=0;        for(sum=0;sum<=tot;sum++)        {            if(SPFA())            {                flag=1;                printf("%d\n",sum);break;            }        }        if(!flag)        puts("No Solution!");    }}

本题是差分约束系统的经典题,复杂度够,所以不用二分,本题务必重新手打,连边操作比较烦,我的SPFA是倒着来的,其实是可以正着来的,此时我们只需要赋dis[0]为0,跑最短路,判dis[24]是不是sum就可以过了。

原创粉丝点击