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(最小割唯一性判断)的主要内容,如果未能解决你的问题,请参考以下文章

[ZOJ2587]Unique Attack

ZOJ 2849-Attack of Panda Virus

洛谷P2587 [ZJOI2008] 泡泡堂

[luoguP2587] [ZJOI2008]泡泡堂(贪心)

ZOJ 3204 Connect them(最小生成树+最小字典序)

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