现在的位置: 首页 > 综合 > 正文

ZOJ-2587 Unique Attack 最小割的唯一性判定

2013年05月20日 ⁄ 综合 ⁄ 共 2006字 ⁄ 字号 评论关闭

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

解法:在求出最大流的基础上,从源点进行一次搜索,搜索按照未饱和的边进行,得到顶点子集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;        
}

 

【上篇】
【下篇】

抱歉!评论已关闭.