poj1275(差分约束)

POJ1275出纳员的雇佣【差分约束】

出纳员的雇佣

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
 
(先每个时间段加一以便C++操作)
差分约束:
0 <= S[i]-S[i-1]<=W[i];      // 雇佣的人数少于申请者但不能为负数
S[i]-S[i-8]>=R[i]               // 当i>=8时,该方程成立,否则将出现负数显然不成立
S[i+16]-S[i]<=x-R[i]   // 当i<8时,由于昨天的雇人可以通宵上班,因此这个约束通过反面处理
S[24] - S[0] >=x                     // 最后24小时内雇佣人应该大于等于x个人
S[i]-S[j]<=K 则从顶点j向i引一条权值为K的边。该系统是否成立也就在于是否存在负环,于是用SPFA判断负环。
然而x(也就是答案)未知,而x<=1000,所以可以二分查找找出最小的x。注意归零。
 
 
要讲一下的就是这个s[i+16]-s[i]<=x-R[i]
因为,我们的s[i]是表示1……i的人数和,那么要搞出s[i]-(昨天的)s[i-8],,,即s[i]-s[i+16],,但s[i]是第二天的
所以s[i]+x-s[i+16]>=R[i]
变形一下就成了s[i+16]-s[i]<=x-R[i]
 
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<queue>
using namespace std;

const int maxn=30;

int tu[maxn][maxn],cnt[maxn],go[maxn][maxn],vis[maxn],dis[maxn];
int n,m,r[maxn],s[maxn];
queue<int>Q;

bool spfa(int x){
     memset(tu,0,sizeof(tu));
     memset(vis,0,sizeof(vis));
     memset(dis,0x3f,sizeof(vis));
     memset(cnt,0,sizeof(cnt));
     vis[24]=1;
     cnt[24]=1;
     dis[24]=0;
     Q.push(24);
     for (int i=1;i<=24;i++) tu[i-1][i]=s[i];
     for (int i=8;i<=24;i++) tu[i][i-8]=-r[i];
     for (int i=1;i<=7;i++) tu[i][i+16]=x-r[i];
     tu[24][0]=-x;
     while(!Q.empty()){
        int u=Q.front();
        Q.pop();
        vis[u]=false;
        for (int i=0;i<=24;i++){
            if(go[u][i]&&dis[i]>dis[u]+tu[u][i]){
                    dis[i]=dis[u]+tu[u][i];
                if(!vis[i]){
                    Q.push(i);
                    cnt[i]++;
                    vis[i]=true;
                    if(cnt[i]>25) return false;
                }
            }
        }
     }
     return true;
}

int main(){
    int t;
    scanf("%d",&t);
    for (int i=1;i<=24;i++) go[i][i-1]=go[i-1][i]=true;
    for (int i=8;i<=24;i++) go[i][i-8]=true;
    for (int i=1;i<=7;i++)  go[i][i+16]=true;
    go[24][0]=true;
    while(t--){
        memset(s,0,sizeof(s));
        int n;
        int x;
        for (int i=1;i<=24;i++) scanf("%d",&r[i]);
        scanf("%d",&n);
        for (int i=1;i<=n;i++) {
                scanf("%d",&x);
                s[x+1]++;
        }
        int l=1;
        int r=n;
        bool falg=false;
        int mid;
        while(l<=r){
            mid=(l+r)/2;
            if(spfa(mid)) {
                    r=mid-1;
                    falg=true;
            }
            else l=mid+1;
        }
        if(falg) printf("%d\n",l);
        else printf("No Solution\n");
    }
return 0;
}

 

posted @ 2018-08-01 21:36  lmjer  阅读(271)  评论(0编辑  收藏  举报