题目链接: 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 }