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

http://acm.zju.edu.cn/onlinejudge/showProblem.do?problemCode=2587

题意:
判断最小割是否唯一。

思路:

最小割唯一性的判断是先跑一遍最大流,然后在残留网络中分别从源点和汇点出发dfs,只有当该边还有流量可用时可以访问下一个顶点,最后如果所有顶点都访问了,那么就是唯一的,否则不唯一。

接下来图解一下:

先看下面这个容量均为1的图:

跑一遍最大流后的残留网络如下(只画正向弧):

接下来从源点和汇点出发都无法访问任何顶点,因为剩余流量皆为0了。这种情况下最小割是不唯一的,很明显,这图我们可以找到很多最小割。

接下来看另外一个残留网络(只画正向弧):

在这个网络中我们就可以遍历所有点,所以它的最小割是唯一的,也就是:

  1 #include<iostream>
  2 #include<algorithm>
  3 #include<cstring>
  4 #include<cstdio>
  5 #include<sstream>
  6 #include<vector>
  7 #include<stack>
  8 #include<queue>
  9 #include<cmath>
 10 #include<map>
 11 #include<set>
 12 using namespace std;
 13 typedef long long ll;
 14 typedef pair<int,int> pll;
 15 const int INF = 0x3f3f3f3f;
 16 const int maxn = 1000 + 5;
 17
 18 int n, m, a, b;
 19 int vis[maxn];
 20
 21 struct Edge
 22 {
 23     int from,to,cap,flow;
 24     Edge(int u,int v,int w,int f):from(u),to(v),cap(w),flow(f){}
 25 };
 26
 27 struct Dinic
 28 {
 29     int n,m,s,t;
 30     vector<Edge> edges;
 31     vector<int> G[maxn];
 32     bool vis[maxn];
 33     int cur[maxn];
 34     int d[maxn];
 35
 36     void init(int n)
 37     {
 38         this->n=n;
 39         for(int i=0;i<n;++i) G[i].clear();
 40         edges.clear();
 41     }
 42
 43     void AddEdge(int from,int to,int cap)
 44     {
 45         edges.push_back( Edge(from,to,cap,0) );
 46         edges.push_back( Edge(to,from,0,0) );
 47         m=edges.size();
 48         G[from].push_back(m-2);
 49         G[to].push_back(m-1);
 50     }
 51
 52     bool BFS()
 53     {
 54         queue<int> Q;
 55         memset(vis,0,sizeof(vis));
 56         vis[s]=true;
 57         d[s]=0;
 58         Q.push(s);
 59         while(!Q.empty())
 60         {
 61             int x=Q.front(); Q.pop();
 62             for(int i=0;i<G[x].size();++i)
 63             {
 64                 Edge& e=edges[G[x][i]];
 65                 if(!vis[e.to] && e.cap>e.flow)
 66                 {
 67                     vis[e.to]=true;
 68                     d[e.to]=d[x]+1;
 69                     Q.push(e.to);
 70                 }
 71             }
 72         }
 73         return vis[t];
 74     }
 75
 76     int DFS(int x,int a)
 77     {
 78         if(x==t || a==0) return a;
 79         int flow=0, f;
 80         for(int &i=cur[x];i<G[x].size();++i)
 81         {
 82             Edge &e=edges[G[x][i]];
 83             if(d[e.to]==d[x]+1 && (f=DFS(e.to,min(a,e.cap-e.flow) ) )>0)
 84             {
 85                 e.flow +=f;
 86                 edges[G[x][i]^1].flow -=f;
 87                 flow +=f;
 88                 a -=f;
 89                 if(a==0) break;
 90             }
 91         }
 92         return flow;
 93     }
 94
 95     int Maxflow(int s,int t)
 96     {
 97         this->s=s; this->t=t;
 98         int flow=0;
 99         while(BFS())
100         {
101             memset(cur,0,sizeof(cur));
102             flow +=DFS(s,INF);
103         }
104         return flow;
105     }
106 }DC;
107
108 void dfs_s(int u)
109 {
110     vis[u]=1;
111     for(int i=0;i<DC.G[u].size();i++)
112     {
113         Edge& e=DC.edges[DC.G[u][i]];
114         if(!vis[e.to] && e.cap>0 && e.cap>e.flow)
115             dfs_s(e.to);
116     }
117 }
118
119 void dfs_t(int u)
120 {
121     vis[u]=1;
122     for(int i=0;i<DC.G[u].size();i++)
123     {
124         Edge& e=DC.edges[DC.G[u][i]];
125         int tmp=DC.G[u][i];
126         if(!vis[e.to] && e.cap==0 && DC.edges[tmp^1].cap>DC.edges[tmp^1].flow)  //用正向弧判断
127             dfs_t(e.to);
128     }
129 }
130
131
132
133 int main()
134 {
135     //freopen("in.txt","r",stdin);
136     while(~scanf("%d%d%d%d",&n,&m,&a,&b) && (n+m+a+b))
137     {
138         int src=a, dst=b;
139         DC.init(n+5);
140
141         for(int i=1;i<=m;i++)
142         {
143             int u, v, w;
144             scanf("%d%d%d",&u,&v,&w);
145             DC.AddEdge(u,v,w);
146             DC.AddEdge(v,u,w);
147         }
148
149         DC.Maxflow(src,dst);
150
151         memset(vis,0,sizeof(vis));
152
153         dfs_s(src);
154         dfs_t(dst);
155
156         bool flag=true;
157         for(int i=1;i<=n;i++)
158         if(!vis[i])  {flag=false;break;}
159
160         if(flag)  printf("UNIQUE\n");
161         else printf("AMBIGUOUS\n");
162     }
163     return 0;
164 }
时间: 2024-08-19 00:32:31

ZOJ 2587 Unique Attack(最小割唯一性判断)的相关文章

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 2587 Unique Attack (判断最小割的唯一性)

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

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

很裸的判断最小割是否唯一.判断方法是先做一遍最大流求最小割,然后从源点和汇点分别遍历所有能够到达的点,看是否覆盖了所有的点,如果覆盖了所有的点,那就是唯一的,否则就是不唯一的. #include <cstdio> #include <cstring> #include <cmath> #include <algorithm> #include <climits> #include <string> #include <iostr

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 2676 Network Wars(最小割,01分数规划)

http://acm.zju.edu.cn/onlinejudge/showProblem.do?problemCode=2676 大致题意:给出一个带权无向图,每条边有一个边权wi,求将S和T分开的一个割边集C,使得该割边集的平均边权最小,即最小化∑wi / |C| . 详见amber关于最小割模型的论文 思路:amber论文中详细讲解了如何转化成函数及建图,值得注意的是当边被重新赋权后,对于wi < 0 的边权,该边必然在最小割中,不必再建边,直接加入最大流中即可,因为求最小割时边权都为正值

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

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

ZOJ 3792 Romantic Value 最小割+求割边的数量

点击打开链接 Romantic Value Time Limit: 2 Seconds      Memory Limit: 65536 KB Farmer John is a diligent man. He spent a lot of time building roads between his farms. From his point of view, every road is romantic because the scenery along it is very harmon

ZOJ 3792 Romantic Value 最小割(最小费用下最小边数)

求最小割及最小花费 把边权c = c*10000+1 然后跑一个最小割,则flow / 10000就是费用 flow%10000就是边数. 且是边数最少的情况.. #include<stdio.h> #include<string.h> #include<iostream> #include<math.h> #include<algorithm> #include<queue> #include<vector> using

zoj 2676 Network Wars 最小割+0-1分数规划

题目链接: http://acm.zju.edu.cn/onlinejudge/showProblem.do?problemCode=2676 题意: 给出N个点和M条边,要求一个割集,使得集合中 ans = 所有边点权值和/边的数量 最小. 思路: 0-1分数规划. 具体证明参考 胡伯涛 <最小割模型在信息学竞赛中的应用> 设g = min(Σwi/Σ1) 转化为 求g使得 (Σwi - g*Σ1) = 0. 所以二分求g的值. 每次建图的时候,以1为源点,N为汇点. 原来图中每条边的容量