zoukankan      html  css  js  c++  java
  • [hdu4598]二分图判定,差分约束

    题意: 给一个图,问能否给每个点分配一个实数值,使得存在一个数实数T,所有点满足:|value(i)| < T 且 u,v之间有边<=> |value(u)-value(v)| >= T。(注意等价符号)

    思路:

    由性质可得,两相邻点的分配的值的符号相反,于是先对原图做一个二分图判定,如果是非二分图,则无解。对二分图染色后,假设color[i]=1,则表示i点为正值,color[i]=-1,则表示为负。在已知每个点正负值的基础上,绝对值符号可以去掉,差分约束模型便出来了。这里有个细节,由于是实数,在遇到<和<=的时候比较麻烦,幸运的是我们可以用整数来代替实数,比如条件a < b可以看成是 a <= (b - 1),只要整数范围足够大即可。

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
    86
    87
    88
    89
    90
    91
    92
    93
    94
    95
    96
    97
    98
    99
    100
    101
    102
    103
    104
    105
    106
    107
    108
    109
    110
    111
    112
    113
    114
    115
    116
    117
    118
    119
    120
    121
    122
    123
    124
    125
    126
    127
    128
    129
    130
    #include <iostream>
    #include <cstdio>
    #include <cstring>
    #include <cstdlib>
    #include <queue>
    #include <cmath>
    #include <algorithm>
    using namespace std;
     
    const int T = 12345;
     
    struct Graph {
        vector<vector<int> > G;
        void clear() { G.clear(); }
        void resize(int n) { G.resize(n + 2); }
        void add(int u, int v) { G[u].push_back(v); }
        vector<int> & operator [] (int u) { return G[u]; }
    };
    Graph G, E;
     
    int n;
    bool mark[345][345];
    int vis[345];
     
    void add(int u, int v, int w) {
        G.add(v, u);
        E.add(v, w);
    }
     
    queue<int> Q;
    int D[345], cnt[345];
    bool relax(int u, int v, int w) {
        if (D[u] > D[v] + w) {
            D[u] = D[v] + w;
            return true;
        }
        return false;
    }
    bool SPFA(int s) {
        while (!Q.empty()) Q.pop();
        memset(D, 0x3f, sizeof(D));
        memset(cnt, 0, sizeof(cnt));
        D[s] = 0;
        memset(vis, 0, sizeof(vis));
        vis[s] = 1;
        cnt[s] ++;
        Q.push(s);
        while (!Q.empty()) {
            int node = Q.front(); Q.pop();
            vis[node] = 0;
            int sz = G[node].size();
            for (int i = 0; i < sz; i ++) {
                int u = G[node][i];
                if (relax(u, node, E[node][i])) {
                    if (!vis[u]) {
                        vis[u] = 1;
                        cnt[u] ++;
                        if (cnt[u] > n) return false;
                        Q.push(u);
                    }
                }
            }
        }
        return true;
    }
     
    bool Color(int k, int c) {
        vis[k] = c;
        for (int i = 0; i < n; i ++) {
            if (mark[k][i]) {
                if (vis[i]) {
                    if (vis[i] == vis[k]) return false;
                }
                else if (!Color(i, -c)) return false;
            }
        }
        return true;
    }
     
    bool check() {
        memset(vis, 0, sizeof(vis));
        for (int i = 0; i < n; i ++) {
            if (!vis[i]) {
                if (!Color(i, 1)) return false;
            }
        }
        G.clear();
        E.clear();
        G.resize(n);
        E.resize(n);
         // 添加一个源点编号为 n, 并从源点引出n条到每个点的有向边,边权为0
        for (int i = 0; i < n; i ++) {
            add(i, n, 0);
        }
        for (int i = 0; i < n; i ++) {
            for (int j = i + 1; j < n; j ++) {
                if (mark[i][j]) {
                    if (vis[i] > 0) add(j, i, -T);
                    else add(i, j, -T);
                }
                else {
                    if (vis[i] > 0) add(i, j, T - 1);
                    else add(j, i, T - 1);
                }
            }
        }
        n ++; // 多了一个源点
        return SPFA(n - 1);
    }
     
    int main() {
    #ifndef ONLINE_JUDGE
        freopen("in.txt""r", stdin);
    #endif // ONLINE_JUDGE
        int T;
        cin >> T;
        while (T --) {
            cin >> n;
            memset(mark, 0, sizeof(mark));
            for (int i = 0; i < n; i ++) {
                char s[345];
                scanf("%s", s);
                for (int j = 0; j < n; j ++) {
                    mark[i][j] = s[j] == '1';
                }
            }
            puts(check()? "Yes" "No");
        }
        return 0;
    }
  • 相关阅读:
    Connected Components? Codeforces
    洛谷 P1344 [USACO4.4]追查坏牛奶Pollutant Control
    洛谷 P4174 [NOI2006]最大获利 && 洛谷 P2762 太空飞行计划问题 (最大权闭合子图 && 最小割输出任意一组方案)
    表达式求值
    费用流(自用,勿看)
    二分图??(自用,勿看)
    C 标准库
    Linux-socket使用
    C 标准库
    C 标准库
  • 原文地址:https://www.cnblogs.com/jklongint/p/4553596.html
Copyright © 2011-2022 走看看