• ZOJ2587 Unique Attack 最小割的唯一性判定


    题意:给定一个无向图,要求判定分离两个点的最小割是否唯一。

    解法:在求出最大流的基础上,从源点进行一次搜索,搜索按照未饱和的边进行,得到顶点子集S的顶点个数;再从汇点反向搜索未饱和的边,得到子集T的顶点个数,判定顶点数相加是否等于总共的顶点数。

    http://blog.csdn.net/waitfor_/article/details/7330437的文章写的很好,这里截取文中所画的两个图进行说明。

    (1)正向搜索集合为S,反向搜索集合为T,cnt1和cnt2都是最小割边。很显然M还存在着最小割边,因为从M到T的残余网络也没有流向T的容量了。

    (2)增加E1这部分边的容量将直接导致网络最大流量增加。增加E2和E3则不然。同样M中存在并上E1后为割边的边集。

    (3)两条割边完全重合为一条,此时网络中的割边唯一。

    代码如下:

    View Code
    #include <cstdlib>
    #include <cstring>
    #include <cstdio>
    #include <iostream>
    #include <algorithm>
    using namespace std;
    
    const int SS = 805, TT = 806;
    const int INF = 0x3fffffff;
    int N, M, A, B;
    
    struct Edge {
        int v, c, next;    
    };
    Edge e[30000];
    int idx, head[810], lv[810];
    int front, tail, que[810];
    int vis[810];
    
    void insert(int a, int b, int c) {
        e[idx].v = b, e[idx].c = c;
        e[idx].next = head[a];
        head[a] = idx++;
    }
    
    bool bfs() {
        memset(lv, 0xff, sizeof (lv));
        front = tail = lv[SS] = 0;
        que[tail++] = SS;
        while (front < tail) {
            int u = que[front++];
            for (int i = head[u]; i != -1; i = e[i].next) {
                int v = e[i].v;
                if (!(~lv[v]) && e[i].c) {
                    lv[v] = lv[u] + 1;
                    if (v == TT) return true;
                    que[tail++] = v;    
                }
            }
        }
        return false;
    }
    
    int dfs(int u, int sup) {
        if (u == TT) return sup;
        int tf = 0, f;
        for (int i = head[u]; i != -1; i = e[i].next) {
            int v = e[i].v;
            if (lv[u]+1==lv[v] && e[i].c && (f=dfs(v, min(e[i].c, sup-tf)))) {
                tf += f;
                e[i].c -= f, e[i^1].c += f;
                if (tf == sup) return sup;    
            }
        }
        if (!tf) lv[u] = -1;
        return tf;
    }
    
    void dinic() {
        int ret = 0;
        while (bfs()) {
            ret += dfs(SS, INF);    
        }
    //    printf("ret = %d\n", ret); 
    }
    
    void flood(int u, int &cnt) {
        for (int i = head[u]; i != -1; i = e[i].next) {
            if (e[i].c && !vis[e[i].v])    {
                ++cnt;
                vis[e[i].v] = 1;
                flood(e[i].v, cnt);
            }
        }
    }
    
    void flood_r(int u, int &cnt) {
        for (int i = head[u]; i != -1; i = e[i].next) {
            if (e[i^1].c && !vis[e[i].v])    {
                ++cnt;
                vis[e[i].v] = 1;
                flood_r(e[i].v, cnt);
            }
        }
    }
    
    bool query() {
        int cnta = 0, cntb = 0; // 分别为从两个方向进行搜索而计数
        memset(vis, 0, sizeof (vis));
        vis[SS] = vis[TT] = 1;
        flood(SS, cnta);
        memset(vis, 0, sizeof (vis));
        vis[SS] = vis[TT] = 1;
        flood_r(TT, cntb);
        return cnta + cntb == N;
    }
    
    int main() {
        while (scanf("%d %d %d %d", &N, &M, &A, &B), N|M|A|B) {
            int a, b, c;
            idx = 0;
            memset(head, 0xff, sizeof (head));
            insert(SS, A, INF), insert(A, SS, 0);
            insert(B, TT, INF), insert(TT, B, 0);
            for (int i = 0; i < M; ++i) {
                scanf("%d %d %d", &a, &b, &c);
                insert(a, b, c), insert(b, a, c);
            }
            dinic();
            printf(query() ? "UNIQUE\n" : "AMBIGUOUS\n");
        }
        return 0;        
    }
  • 相关阅读:
    旋转卡壳(1)求凸包(点集)直径 poj 2187
    求解平面最近点对的问题
    java中的内部类初识
    java中的多重继承
    ObjectiveC中的Protocols
    Mac中配置java的src.jar
    Mac OS X Lion无线网络问题
    Xcode中修改默认文件头部注释
    全文索引查询和like查询对比
    获取Repeater选中行索引
  • 原文地址:https://www.cnblogs.com/Lyush/p/3053640.html
Copyright © 2020-2023  润新知