zoukankan      html  css  js  c++  java
  • BZOJ 4500: 矩阵 差分约束

    题目链接:

    http://www.lydsy.com/JudgeOnline/problem.php?id=4500

    题解:

    从行向列建边,代表一个格子a[i][j],对每个顶点的所有操作可以合并在一起用sum[xi]表示,

    那么题目相当于是要求sum[xi]+sum[xj]==a[xi][xj];

    等价于:sum[xj]-(-sum[xi])==a[xi][xj]

    等价于:sum[xj]-sum'[xi]<=a[xi][xj] && sum[xj]-sum'[xi]>=a[xi][xj]

    等价于:sum[xj]<=sum'[xi]+w && sum'[xi]<=sum[xj]+(-w)

    所有就可以用差分约束来做了。跑一遍最短路,判一下负环就可以了。

    #include<iostream>
    #include<cstring>
    #include<cstdio>
    #include<vector>
    #include<queue>
    using namespace std;
    
    const int maxn = 2222;
    const int INF = 0x3f3f3f3f;
    
    struct Edge {
        int v, w;
        Edge(int v, int w) :v(v), w(w) {}
        Edge() {}
    };
    
    int n, m,k;
    vector<Edge> egs;
    vector<int> G[maxn];
    
    void addEdge(int u, int v, int w) {
        G[u].push_back(egs.size());
        egs.push_back(Edge(v,w));
    }
    
    bool inq[maxn];
    int cnt[maxn];
    int d[maxn];
    bool spfa() {
        memset(inq, 0, sizeof(inq));
        memset(cnt, 0, sizeof(cnt));
        for (int i = 0; i <= n + m; i++) d[i] = INF;
        queue<int> Q;
        d[0] = 0; inq[0] = true; Q.push(0);
        while (!Q.empty()) {
            int u = Q.front(); Q.pop();
            inq[u] = false;
            for (int i = 0; i < G[u].size(); i++) {
                Edge& e = egs[G[u][i]];
                if (d[e.v] > d[u] + e.w) {
                    d[e.v] = d[u] + e.w;
                    if (!inq[e.v]) {
                        Q.push(e.v);
                        inq[e.v] = true;
                        if (++cnt[e.v] > n+m+1) {
                            return false;
                        }
                    }
                }
            }
        }
        return true;
    }
    
    void init() {
        for (int i = 0; i <= n + m; i++) G[i].clear();
        egs.clear();
    }
    
    int main() {
        int tc;
        scanf("%d", &tc);
        while (tc--) {
            scanf("%d%d%d", &n, &m, &k);
            init();
            for (int i = 0; i < k; i++) {
                int u, v, w;
                scanf("%d%d%d", &u, &v, &w);
                addEdge(u, v+n, w);
                addEdge(v+n, u, -w);
            }
            for (int i = 1; i <= n + m; i++) {
                addEdge(0, i, 0);
            }
            if (spfa()) {
                puts("Yes");
            }
            else {
                puts("No");
            }
        }
        return 0;
    }
    
    /*
    2
    2 2 4
    1 1 0
    1 2 0
    2 1 2
    2 2 2
    2 2 4
    1 1 0
    1 2 0
    2 1 2
    2 2 1
    */
  • 相关阅读:
    c语言实现双色球和大乐透
    字符串数组的三种内存模型
    c语言实现数组的排序
    C语言实现二级指针表示字符串数组
    c语言实现字符指针(字符串)数组的排序
    Windows Defender检查文件和应用要管理员设置
    java方法学习1
    The second day of studing English
    Selenium-通过classname定位注意的小问题
    Selenium-ChromeWebDriver
  • 原文地址:https://www.cnblogs.com/fenice/p/5536610.html
Copyright © 2011-2022 走看看