• 【题解】ZOJ1420 Cashier Employment


      论文——冯威《浅析差分约束系统》。

      论文讲得很详细,就不解释了。主要想记录一下对于差分约束的理解(感觉以前的学习真的是在囫囵吞枣啊……)

      差分约束系统,同于解决线性的不等关系是否存在合法解 & 求得最大 / 最小解。当其中牵涉到的式子形如 (A[i] - A[i - 1] >= (<=) x) 时,就可以运用差分约束求解了。处理的方法是由于这个式子为三角形不等式,即spfa中的松弛操作,所以我们看做一个图论的问题,跑最长路 最短路即可。连边的方式自己画图感知就好了。

      当需要求解最大 / 最小值时:最大值运用最短路,最小值运用最长路。以求最大值为例:一个数能够取得的最大值即在满足了最小的约束情况下可以取得的最大值,而道路边权即为约束边,所以为最短路。

      通用解法:1.罗列出不等关系(注意要找全了)。2.移项,未知数一边,常数一边。3.考虑运用最长路 / 最短路求解。这题主要在于构建出方程与函数来描述不等关系的特征,当常数中有未知项时,可以考虑枚举求解(其实这个思想很重要,数据范围小的时候一定考虑枚举暴力呀)。当然这题由于满足单调性,所以二分一下~

    #include <bits/stdc++.h>
    using namespace std;
    #define maxn 300000
    int cnp = 1, head[maxn], num[maxn];
    int R[maxn], dis[maxn], in[maxn];
    bool vis[maxn];
    
    struct edge
    {
        int to, last, co;
    }E[maxn];
    
    int read()
    {
        int x = 0, k = 1;
        char c;
        c = getchar();
        while(c < '0' || c > '9') { if(c == '-') k = -1; c = getchar(); }
        while(c >= '0' && c <= '9') x = x * 10 + c - '0', c = getchar();
        return x * k;
    }
    
    void add(int u, int v, int w)
    {
        E[cnp].to = v, E[cnp].co = w;
        E[cnp].last = head[u], head[u] = cnp ++;
    }
    
    bool spfa()
    {
        queue <int> q;
        for(int i = 1; i <= 30; i ++)
            dis[i] = -99999999;
        memset(vis, 0, sizeof(vis));
        memset(in, 0, sizeof(in));
        dis[0] = 0, q.push(0);
        while(!q.empty())
        {
            int u = q.front(); q.pop();
            vis[u] = 0;
            for(int i = head[u]; i; i = E[i].last)
            {
                int v = E[i].to;
                if(dis[v] < dis[u] + E[i].co)
                {
                    dis[v] = dis[u] + E[i].co;
                    if(!vis[v])
                    {
                        if(++ in[v] == 26) return 1;
                        vis[v] = 1; q.push(v);
                    } 
                }
            }
        }
        return 0;
    }
    
    void Build(int mid)
    {
        memset(head, 0, sizeof(head)); cnp = 1;
        for(int i = 1; i <= 24; i ++)
        {
            add(i - 1, i, 0);
            add(i, i - 1, -num[i]);
        }
        for(int i = 8; i <= 24; i ++)
            add(i - 8, i, R[i]);
        for(int i = 1; i < 8; i ++)
            add(i + 16, i, R[i] - mid);
        add(0, 24, mid); 
    }
    
    int main()
    {
        int T = read();
        while(T --)
        {
            for(int i = 1; i <= 24; i ++) R[i] = read();
            int n = read();
            memset(num, 0, sizeof(num));
            for(int i = 1; i <= n; i ++)
            {
                int x = read();
                num[x + 1] ++;
            }
            Build(n);
            if(spfa())
            { 
                printf("No Solution
    ");
                continue;
            }
            int l = 0, r = n, ans;
            while(l <= r)
            {
                int mid = (l + r) >> 1;
                Build(mid);
                if(spfa()) l = mid + 1;
                else ans = mid, r = mid - 1;
            }
            printf("%d
    ", ans);
        }
        return 0;
    }
  • 相关阅读:
    [转]C#汉字转拼音的源码
    [转]C# DES 加密/解密类库,支持文件和中文/UNICODE字符,返回BASE64编码字符串
    48瓶子,48种性格
    “识谎”36计
    巧克力有益智商 经常吃可提高大脑计算能力
    调用方未由服务进行身份验证
    揭秘人体24小时使用手册
    [转]C#实现人民币金额小写转大写的代码
    转一篇绝对详细的手工构造PE文件教程
    bat 查找某个进程的ID号
  • 原文地址:https://www.cnblogs.com/twilight-sx/p/9180853.html
Copyright © 2020-2023  润新知