POJ 1275 Cashier Employment 差分约束+二分答案

题意:一家商店在每个小时都需要至少di个人值班,现在有n个人,第j个人可以在fj开始上班,连续工作8个小时,问你要满足商店上班的条件至少需要雇佣多少个人

原题连接:http://poj.org/problem?id=1275

一道比较复杂的查分约束,一开始想着写出每个小时的约束条件,后来发现根本就是牛头不对马嘴。

正解应该是这样:

  设di是第i小时需要的人数,fi是第i小时可以雇佣的最大人数,si是第0-i小时雇佣的人数的和

可以建立这样的约束

  si-si-1 <= fi    人数最多不能超过来应聘的

  si-si-1 >= 0    人数不能为负值

  si-s(i-8)>= di   i>=8 八小时内雇佣的人数大于当前时间点需要的人数

  si-s(i+16)>=di-s24  1<=i<8

但是到了这里约束出现了问题,就是s24是一个未知数,而s24就是我们要求的和,我们要求一个最小的24也就是说

ans <= s24 di - ans >= di - s24,显然要有 si-s(i+16)>=di-ans成立

并且为了保证ans<=s24 s24=s24-s0所以有约束ans<=s24-s0

所以只需要通过枚举ans,然后看差分约束是否可以得到解来判断可行性,枚举的方式用二分即可。

判断可行性使用spfa或者bellmanford就可以

#include <cstdio>
#include <cstring>
#include <cmath>
#include <algorithm>
#include <climits>
#include <string>
#include <iostream>
#include <map>
#include <cstdlib>
#include <list>
#include <set>
#include <queue>
#include <stack>

using namespace std;

typedef long long LL;
const int maxn = 25;
const int maxm = 4e3;
const int INF = INT_MAX / 4;
int first[maxn],nxt[maxm],w[maxm],v[maxm];
int d[maxn],n,cnt[maxn],ecnt,qcnt[maxn],a[maxn];
bool inq[maxn];

void adde(int a,int b,int c) {
    w[ecnt] = c; v[ecnt] = b;
    nxt[ecnt] = first[a];
    first[a] = ecnt;
    ecnt++;
}

bool bellmanford() {
    for(int i = 0;i <= 24;i++) d[i] = INF;
    d[0] = 0;
    for(int i = 0;i <= 24;i++) {
        for(int j = 0;j <= 24;j++) {
            for(int k = first[j];k != -1;k = nxt[k]) {
                if(d[v[k]] > d[j] + w[k]) {
                    d[v[k]] = d[j] + w[k];
                }
            }
        }
    }
    for(int i = 0;i <= 24;i++) {
        for(int j = first[i];j != -1;j = nxt[j]) {
            if(d[v[j]] > d[i] + w[j]) return false;
        }
    }
    return true;
}

bool ok(int sum) {
    int necnt = ecnt,tmpnxt[maxm],tmpfirst[maxn];
    memcpy(tmpnxt,nxt,sizeof(nxt));
    memcpy(tmpfirst,first,sizeof(first));
    for(int i = 0;i < 24;i++) {
        int j = (i + 7) % 24 + 1;
        if(j > i) adde(j,i,-a[j]);
        else adde(j,i,sum-a[j]);
    }
    //adde(0,24,sum);
    adde(24,0,-sum);
    bool ret = bellmanford();
    ecnt = necnt;
    memcpy(nxt,tmpnxt,sizeof(nxt));
    memcpy(first,tmpfirst,sizeof(first));
    return ret;
}

void solve() {
    int l = 0,r = n;
    while(l < r) {
        int mid = (l + r) >> 1;
        //printf("now is %d %d %d
",l,r,mid);
        if(ok(mid)) r = mid;
        else l = mid + 1;
    }
    if(!ok(l)) puts("No Solution");
    else printf("%d
",l);
}

int main() {
    //freopen("/tmp/in.txt","r",stdin);
    int T; scanf("%d",&T);
    for(int kase = 1;kase <= T;kase++) {
        ecnt = 0;
        memset(first,-1,sizeof(first));
        memset(nxt,-1,sizeof(nxt));
        memset(cnt,0,sizeof(cnt));
        for(int i = 1;i <= 24;i++) {
            scanf("%d",&a[i]);
        }
        scanf("%d",&n);
        for(int i = 1;i <= n;i++) {
            int str; scanf("%d",&str);
            cnt[str + 1]++;
        }
        for(int i = 1;i <= 24;i++) {
            adde(i - 1,i,cnt[i]);
            adde(i,i - 1,0);
        }
        solve();
    }
    return 0;
}

  

原文地址:https://www.cnblogs.com/rolight/p/3861167.html