POJ 1815 求最小点割(拆点+枚举割边)

题目链接: http://poj.org/problem?id=1815

题目大意:

  给定n个人的关系,a,b互相有联系,b,c也互相有联系的话那么a,c也互相有联系(满足传递性),然后给定一个S,T,问最少需要删除多少个人使得S与T没有联系,如果有多种方案,输出字典序最小的。

分析:

  我直接百度的。

  这道题就是一个求源和汇点联通度的题,转换过来就是最大流最小割问题,把求点割转换到边割。

  http://hi.baidu.com/zfy0701/blog/item/a521f230b06dea9fa9018e0e.html

  我的代码还是根据枚举点,使得它不与其他点相连,求最大流看与初始流比较是否减少来判断该点是否属于最小割。更方便的做法还不会,另外fhq在discuss里说了一个很神奇的方法,看不懂。

代码:

poj1815
  1 /*1815    Accepted    640K    782MS    C++    3965B    2012-06-14 17:35:11*/
  2 #include <cstdio>
  3 #include <cstring>
  4 #include <cmath>
  5 #include <iostream>
  6 #include <algorithm>
  7 #include <vector>
  8 using namespace std;
  9 
 10 #define mpair make_pair
 11 #define pii pair<int,int>
 12 #define MM(a,b) memset(a,b,sizeof(a));
 13 typedef long long lld;
 14 typedef unsigned long long u64;
 15 template<class T> bool up_max(T& a,const T& b){return b>a? a=b,1 : 0;}
 16 template<class T> bool up_min(T& a,const T& b){return b<a? a=b,1 : 0;}
 17 #define maxn 410
 18 #define maxm 20010
 19 const int inf= 2100000000;
 20 
 21 int n,m,S,T;
 22 int ST, ED, NV;
 23 int map[maxn][maxn];
 24 int dis[maxn], pre[maxn], gap[maxn], cur[maxn];
 25 
 26 int top, head[maxn];
 27 struct Edge{
 28     int v,w,next;
 29     Edge(){}
 30     Edge(int v,int w,int next): v(v), w(w), next(next){}
 31 }edge[maxm];
 32 void Addedge(int u,int v,int w){
 33     edge[top]= Edge( v, w, head[u] );
 34     head[u]= top++;
 35     edge[top]= Edge( u, 0, head[v] );
 36     head[v]= top++;
 37 }
 38 
 39 int sap(){
 40     int maxflow= 0;
 41     for(int i=0;i<NV;++i) dis[i]= gap[i]= 0, cur[i]= head[i];
 42     int u= pre[ST]= ST;
 43     int v, aug= inf;
 44     gap[0]= NV;
 45     while( dis[ST]<NV ){
 46         for(int &i= cur[u]; i!=-1; i=edge[i].next){
 47             v= edge[i].v;
 48             if( edge[i].w && dis[u]==dis[v]+1 ) break;
 49         }
 50         if( -1 != cur[u] ){
 51             up_min( aug, edge[ cur[u] ].w );
 52             pre[v]= u;
 53             u= v;
 54             if( v==ED ){
 55                 maxflow+= aug;
 56                 for(u=pre[u];v!=ST;v=u,u=pre[u]){
 57                     edge[ cur[u] ].w-= aug;
 58                     edge[ cur[u]^1 ].w+= aug;
 59                 }
 60                 aug= inf;
 61             }
 62         }
 63         else{
 64             int mindis= NV;
 65             for(int i=head[u]; i!=-1; i= edge[i].next){
 66                 int v= edge[i].v;
 67                 if( edge[i].w && up_min( mindis, dis[v] ) )
 68                     cur[u]= i;
 69             }
 70             if( --gap[ dis[u] ] == 0 ) break;
 71             ++gap[ dis[u]= mindis+1 ];
 72             u= pre[u];
 73         }
 74     }
 75     return maxflow;
 76 }
 77 
 78 void Init_graph(){
 79     top= 0;
 80     MM( head, -1 );
 81     ST= 0, ED= n+n+1; NV= n+n+2; ///
 82 
 83     Addedge( ST, S, inf );
 84     Addedge( T+n, ED, inf );
 85     for(int i=1;i<=n;++i){
 86         if( i==S || i==T ) Addedge( i, i+n, inf );
 87         else Addedge( i, i+n, 1 );
 88     }
 89     for(int i=1;i<=n;++i)
 90         for(int j=1;j<=n;++j)
 91             if( map[i][j] && i!=j ) /// i!=j;
 92                 Addedge( i+n, j, inf );
 93 }
 94 
 95 bool mark[maxn];
 96 void Rebuild_graph(int v){
 97     top= 0;
 98     MM( head, -1 );
 99 
100     /// ST= 0, ED= n+n+1, NV= n+n+2;
101     Addedge( ST, S, inf );
102     Addedge( T+n, ED, inf );
103     for(int i=1;i<=n;++i){
104         if( i==S || i==T ) Addedge( i, i+n, inf );
105         else if( i!=v && !mark[i] ) Addedge( i, i+n, 1 );
106     }
107     for(int i=1;i<=n;++i){
108         if( i==v || mark[i] ) continue;
109         for(int j=1;j<=n;++j)
110             if( map[i][j] && i!=j && j!=v && !mark[j] )
111                 Addedge( i+n, j, inf );
112     }
113 }
114 
115 int main()
116 {
117     //freopen("poj1815.in","r",stdin);
118     while( cin>>n>>S>>T ){
119         for(int i=1;i<=n;++i)
120             for(int j=1;j<=n;++j)
121                 scanf("%d", &map[i][j]);
122 
123         if( map[S][T]==1 ){ puts("NO ANSWER!"); continue; }
124 
125         Init_graph();
126         int Flow= sap();
127         if( 0==Flow ){ puts("0"); continue; }
128 
129         fill( mark, mark+1+n, 0 );
130         int cnt= 0;
131         for(int i=1;i<=n;++i){
132             if( i==S || i==T ) continue;
133             Rebuild_graph( i );
134             int tmp= sap();
135             if( up_min( Flow, tmp ) ){
136                 ++cnt;
137                 mark[i]= 1;
138             }
139         }
140 
141         /// output the answer;
142         printf("%d\n", cnt);
143         bool flag= 0;
144         for(int i=1;i<=n;++i){
145             if( mark[i] ){
146                 if( flag ) printf(" ");
147                 else flag= 1;
148                 printf("%d", i);
149             }
150         }
151         puts("");
152     }
153 }
一毛原创作品,转载请注明出处。
原文地址:https://www.cnblogs.com/yimao/p/2549779.html