最小割的相关知识请参见:网络流问题
I. hdu4289 Control
题意:给出一个由n个点,m条边组成的无向图。给出两个点s,t。对于图中的每个点,去掉这个点都需要一定的花费。求至少多少花费才能使得s和t之间不连通。
分析:题意即求最小割,将每个点拆点,点与对应点的边权为去掉该点的花费,原图中所有边的边权赋为无穷大,跑一遍最大流即可。(最大流即最小割)
1 #include<iostream> 2 #include<cstdio> 3 #include<cmath> 4 #include<cstring> 5 6 using namespace std; 7 const int MAXN = 2010; 8 const int MAXM = 1200012; 9 const int INF = 0x3f3f3f3f; 10 struct Edge 11 { 12 int to, next, cap, flow; 13 }edge[MAXM]; 14 int tol; 15 int head[MAXN]; 16 void init() 17 { 18 tol = 2; 19 memset(head, -1, sizeof(head)); 20 } 21 void addedge(int u, int v, int w, int rw=0) 22 { 23 edge[tol].to = v; edge[tol].cap = w; edge[tol].flow = 0; 24 edge[tol].next = head[u]; head[u] = tol++; 25 edge[tol].to = u; edge[tol].cap = rw; edge[tol].flow = 0; 26 edge[tol].next = head[v]; head[v] = tol++; 27 } 28 int Q[MAXN]; 29 int dep[MAXN], cur[MAXN], sta[MAXN]; 30 bool bfs(int s, int t, int n) 31 { 32 int front = 0, tail = 0; 33 memset(dep, -1, sizeof(dep[0])*(n+1)); 34 dep[s] = 0; 35 Q[tail++] = s; 36 while(front < tail) 37 { 38 int u = Q[front++]; 39 for(int i = head[u]; i != -1; i = edge[i].next) 40 { 41 int v = edge[i].to; 42 if(edge[i].cap > edge[i].flow && dep[v] == -1) { 43 dep[v] = dep[u] + 1; 44 if(v == t) return true; 45 Q[tail++] = v; 46 } 47 } 48 } 49 return false; 50 } 51 int dinic(int s, int t, int n) { 52 int maxflow = 0; 53 while(bfs(s, t, n)) { 54 for(int i = 0; i < n; i++) cur[i] = head[i]; 55 int u = s, tail = 0; 56 while(cur[s] != -1) 57 { 58 if(u == t) 59 { 60 int tp = INF; 61 for(int i = tail-1; i >= 0; i--) 62 tp = min(tp, edge[sta[i]].cap-edge[sta[i]].flow); 63 maxflow+=tp; 64 for(int i = tail-1; i >= 0; i--) { 65 edge[sta[i]].flow+=tp; 66 edge[sta[i]^1].flow-=tp; 67 if(edge[sta[i]].cap-edge[sta[i]].flow==0) 68 tail = i; 69 } 70 u = edge[sta[tail]^1].to; 71 } 72 else 73 if(cur[u] != -1 && edge[cur[u]].cap > edge[cur[u]].flow && dep[u] + 1 == dep[edge[cur[u]].to]) 74 { 75 sta[tail++] = cur[u]; 76 u = edge[cur[u]].to; 77 } 78 else 79 { 80 while(u != s && cur[u] == -1) 81 u = edge[sta[--tail]^1].to; 82 cur[u] = edge[cur[u]].next; 83 } 84 } 85 } 86 return maxflow; 87 } 88 int n,m,s,d; 89 90 int main() 91 { 92 while(~scanf("%d%d",&n,&m)) 93 { 94 init(); 95 scanf("%d%d",&s,&d); 96 int c; 97 for(int i=0;i<n;++i) 98 { 99 scanf("%d",&c); 100 addedge(i,i+n,c); 101 } 102 for(int i=1;i<=m;++i) 103 { 104 int a,b; 105 scanf("%d%d",&a,&b); 106 addedge(a-1+n,b-1,INF); 107 addedge(b-1+n,a-1,INF); 108 } 109 cout<<dinic(s-1,d-1+n,2*n)<<endl; 110 } 111 return 0; 112 }
J. UVA10480 Sabotage
题意:旧政府有一个很庞大的网络系统,可以很方便的指挥他的城市,起义军为了减少伤亡所以决定破坏他们的网络,使他们的首都(1号城市)和最大的城市(2号城市)不能联
系,不过破坏不同的网络所花费的代价是不同的,现在起义军想知道最少花费的代价是多少,输出需要破坏的线路。
分析:与 I 题一样,也是求最小割,只要算出最大流即可。不过题目要求输出最小割的边,这也是可以用网络流解决的,方法:求完最大流后,在残留网络中从源点 s 开始 dfs ,将能
到达的点标号( c - f >0 的边),最后遍历一遍边集,将起点被标记、终点未被标记的边输出。(注意这是无向图,边只用输出一遍,而在有向图中,条件应该改为起点标号、终点未标或起点未标、终点标号的边)。
1 #include<iostream> 2 #include<cstdio> 3 #include<cmath> 4 #include<cstring> 5 #include<algorithm> 6 7 using namespace std; 8 const int MAXN = 200; 9 const int MAXM = 5000; 10 const int INF = 0x3f3f3f3f; 11 struct Edge 12 { 13 int from,to, next, cap, flow; 14 }edge[MAXM]; 15 int tol; 16 int head[MAXN]; 17 void init() 18 { 19 tol = 2; 20 memset(head, -1, sizeof(head)); 21 } 22 int min(int a,int b) 23 { 24 return a>b?b:a; 25 } 26 void addedge(int u, int v, int w, int rw=0) 27 { 28 edge[tol].from=u; 29 edge[tol].to = v; edge[tol].cap = w; edge[tol].flow = 0; 30 edge[tol].next = head[u]; head[u] = tol++; 31 } 32 int Q[MAXN]; 33 int dep[MAXN], cur[MAXN], sta[MAXN]; 34 bool bfs(int s, int t, int n) 35 { 36 int front = 0, tail = 0; 37 memset(dep, -1, sizeof(dep[0])*(n+1)); 38 dep[s] = 0; 39 Q[tail++] = s; 40 while(front < tail) 41 { 42 int u = Q[front++]; 43 for(int i = head[u]; i != -1; i = edge[i].next) 44 { 45 int v = edge[i].to; 46 if(edge[i].cap > edge[i].flow && dep[v] == -1) { 47 dep[v] = dep[u] + 1; 48 if(v == t) return true; 49 Q[tail++] = v; 50 } 51 } 52 } 53 return false; 54 } 55 int dinic(int s, int t, int n) { 56 int maxflow = 0; 57 while(bfs(s, t, n)) { 58 for(int i = 0; i < n; i++) cur[i] = head[i]; 59 int u = s, tail = 0; 60 while(cur[s] != -1) 61 { 62 if(u == t) 63 { 64 int tp = INF; 65 for(int i = tail-1; i >= 0; i--) 66 tp = min(tp, edge[sta[i]].cap-edge[sta[i]].flow); 67 maxflow+=tp; 68 for(int i = tail-1; i >= 0; i--) { 69 edge[sta[i]].flow+=tp; 70 edge[sta[i]^1].flow-=tp; 71 if(edge[sta[i]].cap-edge[sta[i]].flow==0) 72 tail = i; 73 } 74 u = edge[sta[tail]].from; 75 } 76 else 77 if(cur[u] != -1 && edge[cur[u]].cap > edge[cur[u]].flow && dep[u] + 1 == dep[edge[cur[u]].to]) 78 { 79 sta[tail++] = cur[u]; 80 u = edge[cur[u]].to; 81 } 82 else 83 { 84 while(u != s && cur[u] == -1) 85 u = edge[sta[--tail]].from; 86 cur[u] = edge[cur[u]].next; 87 } 88 } 89 } 90 return maxflow; 91 } 92 int n,m; 93 bool vis[MAXN]; 94 95 void dfs(int u) 96 { 97 vis[u]=true; 98 for(int i=head[u];i!=-1;i=edge[i].next) 99 { 100 int v=edge[i].to; 101 if(edge[i].cap>edge[i].flow&&(!vis[v])) 102 dfs(v); 103 } 104 } 105 106 int main() 107 { 108 while(~scanf("%d%d",&n,&m)&&n&&m) 109 { 110 init(); 111 for(int i=1;i<=m;++i) 112 { 113 int u,v,c; 114 scanf("%d%d%d",&u,&v,&c); 115 addedge(u-1,v-1,c); 116 addedge(v-1,u-1,c); 117 } 118 dinic(0,1,n); 119 memset(vis,false,sizeof(vis)); 120 dfs(0); 121 for(int i=2;i<tol;i=i+2) 122 { 123 int u=edge[i].from; 124 int v=edge[i].to; 125 if(vis[u]!=vis[v]) 126 { 127 cout<<u+1<<" "<<v+1<<endl; 128 } 129 } 130 cout<<endl; 131 } 132 return 0; 133 }