• 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;
    }
    

      

  • 相关阅读:
    WCF开发入门的实例
    转:SQLHelper类,泛型+反射
    设置ASP缓存的几个语句
    ADO.NET总结
    通过反射来实现:DataTable 和List 相互转换
    十步完成windows服务的安装
    dhl:The request for security token could not be satisfied because authentication failed. 调用方未由服务进行身份验证。
    C#中的readonly(运行时常量)与const(编译时常量)的区别
    用do{}创建内联子程序
    用autodie简化错误处理
  • 原文地址:https://www.cnblogs.com/rolight/p/3861167.html
Copyright © 2020-2023  润新知