zoukankan      html  css  js  c++  java
  • 【题解】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;
    }
  • 相关阅读:
    【转】虚拟机 NAT网络设置
    [转载]应用 Valgrind 发现 Linux 程序的内存问题
    Visual Studio 代码格式化插件(等号自动对齐、注释自动对齐等)
    【转】链接任意目录下库文件(解决错误“/usr/bin/ld: cannot find -lxxx”
    C语言实现封装、继承和多态
    美国专利搜索网站
    【转】基于OCS实现高速缓存
    【转】防止网页被搜索引擎、爬虫和网页采集器收录或克隆复制的方法汇总
    [转]机器学习和计算机视觉----数学基础
    [转]机器学习与数据挖掘的学习路线图
  • 原文地址:https://www.cnblogs.com/twilight-sx/p/9180853.html
Copyright © 2011-2022 走看看