上下界网络流 链接
转自:http://blog.csdn.net/leolin_/article/details/7208246
一、有源汇、无源汇的可行流。
求可行流,其实就是问是否存在一个方案可以使所有必须边都满流。对于有源汇的网络,我们可以添加一条边t->s,流量上限为INF,这样就变成了无源汇的网络。对于无源汇的网络,只要对ss到tt求一次最大流,若所有必须边都满流,则有可行解,若要求打印方案,只需将非必须边中流过的流量加上流量下界(必须边已满流)。
二、有源汇的最大流
这里的最大流,前提是使所有必须边满流,再要求从s到t的流量最大(注意,这里所求的最大流是原网络的最大流,而我们求ss到tt的最大流只是用于判断是否能使所有必须边满流)。首先判断所有必须边是否满流,这里和问题一中提到的方法一样,注意这里是有源汇的网络。然后直接对残留网络求一次从s到t的最大流,这个最大流再加上流量下界就是最终答案。
三、有源汇的最小流
和问题二相反,我们要使所有必须边满流的情况下,要求从s到t的流量最小。这个问题比上面的问题都要复杂,分三个步骤。
1、对ss到tt求一次最大流,记为f1。(在有源汇的情况下,先使整个网络趋向必须边尽量满足的情况)
2、添加一条边t->s,流量上限为INF,这条边记为p。(构造无源汇网络)
3、对ss到tt再次求最大流,记为f2。(要判断可行,必须先构造无源汇网络流,因此要再次求最大流)
如果所有必须边都满流,证明存在可行解,原图的最小流为“流经边p的流量”(原图已构造成无源汇网络,对于s同样满足入流 == 出流,只有新添加的边流向s,而s的出流就是原图的最小流)。
Flow construction
8PE!!!!!!!!!!
#include <bits/stdc++.h> using namespace std; const int maxv = 20005; const int maxe = 20005; const int inf = 0x3f3f3f3f; struct Edge{ int u, v, cap, flow, nxt; Edge(int u = 0, int v = 0, int cap = 0, int flow = 0, int nxt = 0) : u(u), v(v), cap(cap), flow(flow), nxt(nxt) {} }e[maxe<<1]; int head[maxv]; int cnt; void init(){ cnt = 0; memset(head, -1, sizeof(head)); } void add(int u, int v, int cap){ e[cnt] = Edge(u, v, cap, 0, head[u]); head[u] = cnt++; e[cnt] = Edge(v, u, 0, 0, head[v]); head[v] = cnt++; } int d[maxv], num[maxv], p[maxv], cur[maxv]; int vis[maxv]; int s, t; int N; void bfs(){ memset(vis, 0, sizeof(vis)); memset(d, -1, sizeof(d)); queue<int> q; q.push(t); d[t] = 0; vis[t] = 1; while(!q.empty()){ int u = q.front(); q.pop(); for(int i = head[u]; ~i; i = e[i].nxt){ int id = i & (-2); int v = e[id].u; if(!vis[v] && e[id].cap > e[id].flow){ vis[v] = 1; d[v] = d[u] + 1; q.push(v); } } } } int augment(){ int u = t, a = inf; while(u != s){ int id = p[u]; a = min(a, e[id].cap - e[id].flow); u = e[id].u; } u = t; while(u != s){ int id = p[u]; e[id].flow += a; e[id ^ 1].flow -= a; u = e[id].u; } return a; } int ISAP(){ bfs(); int flow = 0; memset(num, 0, sizeof(num)); for(int i = 0; i < N; i++){ cur[i] = head[i]; if(~d[i]) num[d[i]]++; } int u = s; while(d[s] < N){ if(u == t){ flow += augment(); u = s; } int ok = 0; for(int i = cur[u]; ~i; i = e[i].nxt){ int v = e[i].v; if(d[u] == d[v] + 1 && e[i].cap > e[i].flow){ ok = 1; p[v] = i; cur[u] = i; u = v; break; } } if(!ok){ int m = N - 1; for(int i = head[u]; ~i; i = e[i].nxt){ if(e[i].cap > e[i].flow && ~d[e[i].v]) m = min(m, d[e[i].v]); } if(--num[d[u]] == 0) break; num[d[u] = m + 1]++; cur[u] = head[u]; if(u != s) u = e[p[u]].u; } } return flow; } int ans[maxe], id[maxe]; int main(){ int n, m; freopen("in.txt", "r", stdin); freopen("out2.txt", "w", stdout); while(scanf("%d %d" , &n, &m) != EOF){ int u, v, cap, d; init(); int S = 0, T = n + 1; int sum = 0; for(int i = 0; i < m; i++){ scanf("%d %d %d %d", &u, &v, &cap, &d); id[i] = maxe - 1; if(d){ sum += cap; add(u, T, cap); add(S, v, cap); ans[i] = cap; }else{ ans[i] = 0; add(u, v, cap); id[i] = cnt - 2; } } s = S; t = T; N = n + 2; int pre = ISAP(); add(n, 1, inf); int res = ISAP(); int flow = res + pre; //cout<<pre<<" "<<res<<" "<<flow<<endl; if(sum == flow){ printf("%d ", res); for(int i = 0; i < m; i++){ printf("%d%c", e[id[i]].flow + ans[i], (i == m-1 ? ' ' : ' ')); } }else{ puts("Impossible"); } } }
Reactor Cooling
求有上下界的无源无汇的最小可行流。
1 #include <bits/stdc++.h> 2 using namespace std; 3 const int maxv = 210; 4 const int maxe = 210 * 210 * 6; 5 const int inf = 0x3f3f3f3f; 6 struct Edge{ 7 int u, v, cap, flow, nxt; 8 Edge(int u = 0, int v = 0, int cap = 0, int flow = 0, int nxt = 0) : 9 u(u), v(v), cap(cap), flow(flow), nxt(nxt) {} 10 }e[maxe]; 11 int head[maxv]; 12 int cnt; 13 void init(){ 14 cnt = 0; 15 memset(head, -1, sizeof(head)); 16 } 17 void add(int u, int v, int cap){ 18 e[cnt] = Edge(u, v, cap, 0, head[u]); 19 head[u] = cnt++; 20 e[cnt] = Edge(v, u, 0, 0, head[v]); 21 head[v] = cnt++; 22 } 23 24 int d[maxv], num[maxv], p[maxv], cur[maxv]; 25 int vis[maxv]; 26 int s, t; 27 int N; 28 29 void bfs(){ 30 memset(vis, 0, sizeof(vis)); 31 memset(d, -1, sizeof(d)); 32 queue<int> q; 33 q.push(t); 34 d[t] = 0; 35 vis[t] = 1; 36 while(!q.empty()){ 37 int u = q.front(); 38 q.pop(); 39 for(int i = head[u]; ~i; i = e[i].nxt){ 40 int id = i & (-2); 41 int v = e[id].u; 42 if(!vis[v] && e[id].cap > e[id].flow){ 43 vis[v] = 1; 44 d[v] = d[u] + 1; 45 q.push(v); 46 } 47 } 48 } 49 } 50 51 int augment(){ 52 int u = t, a = inf; 53 while(u != s){ 54 int id = p[u]; 55 a = min(a, e[id].cap - e[id].flow); 56 u = e[id].u; 57 } 58 u = t; 59 while(u != s){ 60 int id = p[u]; 61 e[id].flow += a; 62 e[id ^ 1].flow -= a; 63 u = e[id].u; 64 } 65 return a; 66 } 67 68 int ISAP(){ 69 bfs(); 70 int flow = 0; 71 memset(num, 0, sizeof(num)); 72 for(int i = 0; i < N; i++){ 73 cur[i] = head[i]; 74 if(~d[i]) num[d[i]]++; 75 } 76 int u = s; 77 while(d[s] < N){ 78 if(u == t){ 79 flow += augment(); 80 u = s; 81 } 82 int ok = 0; 83 for(int i = cur[u]; ~i; i = e[i].nxt){ 84 int v = e[i].v; 85 if(d[u] == d[v] + 1 && e[i].cap > e[i].flow){ 86 ok = 1; 87 p[v] = i; 88 cur[u] = i; 89 u = v; 90 break; 91 } 92 } 93 if(!ok){ 94 int m = N - 1; 95 for(int i = head[u]; ~i; i = e[i].nxt){ 96 if(e[i].cap > e[i].flow && ~d[e[i].v]) m = min(m, d[e[i].v]); 97 } 98 if(num[--d[u]] == 0) break; 99 num[d[u] = m + 1]++; 100 cur[u] = head[u]; 101 if(u != s) u = e[p[u]].u; 102 } 103 } 104 return flow; 105 } 106 107 int ans[maxe], id[maxe]; 108 109 int main(){ 110 int n, m; 111 while(scanf("%d %d" , &n, &m) != EOF){ 112 int u, v, cap, d; 113 init(); 114 int S = 0, T = n + 1; 115 int sum = 0; 116 for(int i = 0; i < m; i++){ 117 scanf("%d %d %d %d", &u, &v, &d, &cap); 118 add(u, v, cap - d); 119 id[i] = cnt - 2; 120 add(u, T, d); 121 add(S, v, d); 122 sum += d; 123 ans[i] = d; 124 } 125 s = S; 126 t = T; 127 N = n + 2; 128 int flow = ISAP(); 129 if(sum == flow){ 130 puts("YES"); 131 for(int i = 0; i < m; i++){ 132 printf("%d ", e[id[i]].flow + ans[i]); 133 } 134 }else{ 135 puts("NO"); 136 } 137 } 138 139 }