ZOJ 2587 Unique Attack 判断最小割是否唯一

很裸的判断最小割是否唯一。判断方法是先做一遍最大流求最小割,然后从源点和汇点分别遍历所有能够到达的点,看是否覆盖了所有的点,如果覆盖了所有的点,那就是唯一的,否则就是不唯一的。

#include <cstdio>
#include <cstring>
#include <cmath>
#include <algorithm>
#include <climits>
#include <string>
#include <iostream>
#include <map>
#include <cstdlib>
#include <list>
#include <set>
#include <queue>
#include <stack>

using namespace std;

typedef long long LL;
const int maxn = 800 + 5;
const int maxm = 80000;
const int INF = INT_MAX / 2;
int n,m,s,t;
int first[maxn],nxt[maxm];
int ecnt,v[maxm],cap[maxm];
int q[maxn],qs,qe;
bool vis[maxn];

void adde(int uu,int vv,int ww) {
    v[ecnt] = vv; cap[ecnt] = ww; nxt[ecnt] = first[uu]; first[uu] = ecnt++;
    v[ecnt] = uu; cap[ecnt] = 0; nxt[ecnt] = first[vv]; first[vv] = ecnt++;
}

int level[maxn];
bool bfs() {
    memset(level,0,sizeof(level));
    qs = qe = 0;
    q[qe++] = s;
    level[s] = 1;
    while(qs < qe) {
        int now = q[qs++];
        if(now == t) break;
        for(int i = first[now];~i;i = nxt[i]) {
            if(cap[i] && level[v[i]] == 0) {
                q[qe++] = v[i]; level[v[i]] = level[now] + 1;
            }
        }
    }
    return level[t];
}

int dfs(int now,int alpha) {
    if(now == t) return alpha;
    int sum = 0;
    for(int i = first[now];~i && alpha;i = nxt[i]) {
        if(cap[i] && level[v[i]] == level[now] + 1) {
            int ret = dfs(v[i],min(alpha,cap[i]));
            sum += ret; alpha -= ret;
            cap[i] -= ret; cap[i ^ 1] += ret;
        }
    }
    if(sum == 0) level[now] = -1;
    return sum;
}

void solve() {
    //先做一遍最大流
    while(bfs()) dfs(s,INF);
    //分别从起点和终点做一遍bfs
    memset(vis,0,sizeof(vis));
    qs = qe = 0;
    q[qe++] = s;
    vis[s] = true;
    while(qs < qe) {
        int now = q[qs++];
        for(int i = first[now];~i;i = nxt[i]) {
            if(cap[i] && !vis[v[i]]) {
                vis[v[i]] = true; q[qe++] = v[i];
            }
        }
    }
    qs = qe = 0;
    q[qe++] = t;
    vis[t] = true;
    while(qs < qe) {
        int now = q[qs++];
        for(int i = first[now];~i;i = nxt[i]) {
            if(cap[i ^ 1] && !vis[v[i]]) {
                vis[v[i]] = true; q[qe++] = v[i];
            }
        }
    }
    for(int i = 1;i <= n;i++) {
        if(!vis[i]) {
            puts("AMBIGUOUS");
            return;
        }
    }
    puts("UNIQUE");
}

int main() {
    while(scanf("%d%d%d%d",&n,&m,&s,&t),n) {
        memset(first,-1,sizeof(first));
        ecnt = 0;
        for(int i = 0;i < m;i++) {
            int a,b,c; scanf("%d%d%d",&a,&b,&c);
            adde(a,b,c); adde(b,a,c);
        }
        solve();
    }
    return 0;
}

ZOJ 2587 Unique Attack 判断最小割是否唯一,布布扣,bubuko.com

时间: 2024-10-02 00:38:09

ZOJ 2587 Unique Attack 判断最小割是否唯一的相关文章

ZOJ 2587 Unique Attack(最小割唯一性判断)

http://acm.zju.edu.cn/onlinejudge/showProblem.do?problemCode=2587 题意:判断最小割是否唯一. 思路: 最小割唯一性的判断是先跑一遍最大流,然后在残留网络中分别从源点和汇点出发dfs,只有当该边还有流量可用时可以访问下一个顶点,最后如果所有顶点都访问了,那么就是唯一的,否则不唯一. 接下来图解一下: 先看下面这个容量均为1的图: 跑一遍最大流后的残留网络如下(只画正向弧): 接下来从源点和汇点出发都无法访问任何顶点,因为剩余流量皆为

zoj2587 Unique Attack 判断最小割是否唯一

题目链接: zoj2587 题意: 给出一张无向网络图,并给出起点和终点,破坏图的每一条边需要一定的费用,问破坏起点和终点的连通性的费用是否唯一. 解题思路: 破坏两点的连通性的最小费用,很容易联想到 网络流中的最小割, 建立源点 汇点 同时 因为图是无向图,我们需要将每条边建两次(正反向). 然后就是判断这个最小割是否唯一了: 首先 从源点开始 dfs  通过非饱和边  统计所有能走到的点  记为s1 然后 从汇点开始 dfs  通过非饱和边  统计所有能走到的点 记为s2 如果s1+s2==

ZOJ 2587 Unique Attack (判断最小割的唯一性)

ZOJ 2587 Unique Attack 链接:http://acm.zju.edu.cn/onlinejudge/showProblem.do?problemId=1587 题意:N 台超级计算机连成一个网络.M 对计算机之间用光纤直接连在一起,光纤的连接是双向的.数据可以直接在有光纤直接连接的计算机之间传输,也可以通过一些计算机作为中转来传输. 有一群恐怖分子计划攻击网络.他们的目标是将网络中两台主计算机断开,这样这两台计算机之间就无法传输数据了.恐怖分子已经计算好了摧毁每条光纤所需要花

zoj 2587 Unique Attack 【判断最小割是否唯一】

Unique Attack Time Limit: 5 Seconds      Memory Limit: 32768 KB N supercomputers in the United States of Antarctica are connected into a network. A network has a simple topology: M different pairs of supercomputers are connected to each other by an o

zoj 2587 Unique Attack 最小割判定

题目链接 让你判断最小割是否唯一. 判断方法是, 先求一遍最大流, 然后从源点dfs一次, 搜索未饱和边的数目. 从汇点dfs一次, 同样也是搜索未饱和边的数目, 看总和是否等于n. 如果等于n那么唯一. 具体可以看这里, http://www.cnblogs.com/Lyush/archive/2013/05/01/3053640.html. 1 #include<bits/stdc++.h> 2 using namespace std; 3 #define mem(a) memset(a,

zoj 3792 Romantic Value(最小割下边数最小)

http://acm.zju.edu.cn/onlinejudge/showProblem.do?problemId=5300 大致题意:给出一个无向图,以及起点与终点.要删除一些边使得起点与终点不连通,在删掉边的权值之和最小的情况下要求删除的边数尽量少.求出一个比值:剩余边数权值和/删除的边数. 思路:删除边的权值之和最小显然是求最小割即最大流.但同时要求删除边数最少,解决方法是把边数也加到权值上去,一起求最大流,因为边数最多是1000,即每条边的边权置为 w*10000+1,1代表这一条边.

zoj 2874 &amp; poj 3308 Paratroopers (最小割)

题意: 一个m*n大小的网格,已知伞兵着陆的具体位置(行和列).现在在某行(或某列) 安装一架激光枪,一架激光枪能杀死该行(或该列)所有的伞兵.在第i行安装一架 激光枪的费用是Ri,在第i列安装的费用是Ci.要安装整个激光枪系统,总费用为这些 激光枪费用的乘积. 求杀死所有伞兵的最小费用. 构图: 把伞兵视为边,行与列视为顶点.增加源点和汇点,对于第i行,从源点向顶点i连接一条 容量为Ri的边.对于第j列,从顶点j向汇点连接一条容量为Rj的边. 如果某一点(i,j)有伞兵降落,则从顶点Ri向顶点

zoj 2587 判断最小割的唯一性

算法: 先求出残量网络,计算出从src能够到的点集A,再求出能够到dst的点集B,如果所有点都被访问到了,那么割就是唯一的,即(A,B),否则(A,V-A)和(V-B,B)都是最小割. (注意因为割的本质是有向边集,而不是点集V的划分,所以(A,V-A)和(V-B,B)有可能本质上还是同一个最小割,比如随便再加一个孤立点,虽然割还是唯一的,但还是有点没有被访问到,所以我们限制原图中所有点要么可以从src到达,要么可以到达dst) 1 #include <cstdio> 2 #include &

ZOJ2587 Unique Attack(判定最小割唯一性)

看了题解,自己大概想了下. 最小割唯一的充分必要条件是残量网络中所有点要嘛能从源点floodfill到要嘛能floodfill到汇点. 必要性,这是当然的,因为假设从源点floodfill或者从汇点反着floodfill得到的集合若不相补,那这就有两个最小割的方案,最小割不唯一. 充分性,首先这样就找到一个最小割,它在两次floodfill的交界处,假设还存在另一个最小割在靠近源点或者靠近汇点处那必然floodfill时找到的是它,这与另一个最小割矛盾,所以仅存在这么一个在交界处的最小割. 于是