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;
    }
  • 相关阅读:
    Java菜鸟之java基础语法,运算符(三)
    Lotus迁移到Exchange 2010 POC 之Domino Server的配置!
    hibernate:对于java.lang.NoSuchMethodError: antlr.collections.AST.getLine()I错误解决办法
    【targeting学习笔记】Display Advertising Targeting
    Domino 迁移到Exchange 之 Domino Admin 安装!
    sqlite3使用详解(Qt版本)
    .net反混淆脱壳工具de4dot的使用
    破解NET的四大神器(转)
    C#让应用程序只运行一个实例的几种方法
    Windows server 2008 R2实现多用户远程连接
  • 原文地址:https://www.cnblogs.com/jklongint/p/4553596.html
Copyright © 2011-2022 走看看