ZOJ 2587 Unique Attack(最小割唯一性判断)
Posted 谦谦君子,陌上其华
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了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 }
以上是关于ZOJ 2587 Unique Attack(最小割唯一性判断)的主要内容,如果未能解决你的问题,请参考以下文章
ZOJ 2849-Attack of Panda Virus
[luoguP2587] [ZJOI2008]泡泡堂(贪心)