白书二代上提到了无源无汇有容量下界网络可行流和有容量下界网络的s-t最大/最小流问题。
但是由于本人智商捉鸡,觉得LRJ大神写的似乎不是很好理解,所以只能找一些题目来帮助自己理解理解了。
这里直说方法,证明。。。不会。
1.无源无汇有容量下界可行流
这个问题的解法在周源的那个论文里讲的很清楚了。
对于每条边,都有一个容量下界b和一个容量上界c,那么这条边实际的可行流量只有c-b,剩下的b必须满流。
对每个点i,求a = sum(流向它的下界流)-sum(从它流出的下界流量)
若a>0,从源点0连一条到i的容量为a的边
若a<0,从i连一条到汇点n+1的容量为-a的边
(我觉得其实这里都是为求自由流做的准备)
然后求一次最大流,若所有从源点出发的点都满流,则有可行流,每条边的可行流为求最大流后的实际流量flow+该边的流量下界b
题目:ZOJ 2314
代码:
1 #include <iostream> 2 #include <cstdio> 3 #include <cstring> 4 #include <vector> 5 #include <queue> 6 #define maxn 210 7 #define INF 100000000 8 using namespace std; 9 10 struct Edge{ 11 int from,to,cap,flow; 12 }; 13 14 struct Dinic{ 15 int n,m,s,t; 16 vector<Edge> edges; 17 vector<int> G[maxn]; 18 bool vis[maxn]; 19 int d[maxn]; 20 int cur[maxn]; 21 22 void ClearAll(int n){ 23 for(int i = 0;i < n;i++) G[i].clear(); 24 edges.clear(); 25 } 26 27 void add_edge(int from,int to,int cap){ 28 edges.push_back((Edge){from,to,cap,0}); 29 edges.push_back((Edge){to,from,0,0}); 30 m = edges.size(); 31 G[from].push_back(m-2); 32 G[to].push_back(m-1); 33 } 34 35 bool BFS(){ 36 memset(vis,0,sizeof(vis)); 37 queue<int> Q; 38 Q.push(s); 39 vis[s] = 1; 40 d[s] = 0; 41 while(!Q.empty()){ 42 int x = Q.front();Q.pop(); 43 for(int i = 0;i < G[x].size();i++){ 44 Edge& e = edges[G[x][i]]; 45 if(!vis[e.to] && e.cap > e.flow){ 46 vis[e.to] = 1; 47 d[e.to] = d[x] + 1; 48 Q.push(e.to); 49 } 50 } 51 } 52 return vis[t]; 53 } 54 55 int DFS(int x,int a){ 56 if(x == t || a == 0) return a; 57 int flow = 0,f; 58 for(int &i = cur[x];i < G[x].size();i++){ 59 Edge& e = edges[G[x][i]]; 60 if(d[x] + 1 == d[e.to] && (f = DFS(e.to,min(a,e.cap-e.flow))) > 0){ 61 e.flow += f; 62 edges[G[x][i]^1].flow -= f; 63 flow += f; 64 a -= f; 65 if(a == 0) break; 66 } 67 } 68 return flow; 69 } 70 71 int Maxflow(int s,int t){ 72 this->s = s;this->t = t; 73 int flow = 0; 74 while(BFS()){ 75 memset(cur,0,sizeof(cur)); 76 flow += DFS(s,INF); 77 } 78 return flow; 79 } 80 }; 81 82 Dinic g; 83 int in[maxn],flow[50000],low[50000]; 84 int main() 85 { 86 int T,n,m,a,b,c; 87 scanf("%d",&T); 88 while(T--){ 89 scanf("%d%d",&n,&m); 90 memset(in,0,sizeof(in)); 91 g.ClearAll(n+2); 92 for(int i = 0;i < m;i++){ 93 scanf("%d%d%d%d",&a,&b,&low[i],&c); 94 in[a] -= low[i]; 95 in[b] += low[i]; 96 g.add_edge(a,b,c-low[i]); 97 } 98 for(int i = 1;i <= n;i++){ 99 if(in[i] > 0) g.add_edge(0,i,in[i]); 100 if(in[i] < 0) g.add_edge(i,n+1,-in[i]); 101 } 102 g.Maxflow(0,n+1); 103 bool flag = true; 104 for(int i = 0;i < g.G[0].size();i++){ 105 //printf("%d %d ",g.edges[g.G[0][i]].cap,g.edges[g.G[0][i]].flow); 106 if(g.edges[g.G[0][i]].flow != g.edges[g.G[0][i]].cap){ 107 flag = false; 108 break; 109 } 110 } 111 if(flag){ 112 printf("YES "); 113 for(int i = 0;i < m;i++){ 114 printf("%d ",low[i] + g.edges[i*2].flow); 115 } 116 }else{ 117 printf("NO "); 118 } 119 printf(" "); 120 } 121 return 0; 122 }
2.有源汇有下界的最大流问题
(1)首先假设真正的源点和汇点分别为s和t,跟上面一样:
对于每条边,都有一个容量下界b和一个容量上界c,那么这条边实际的可行流量只有c-b,剩下的b必须满流。
对每个点i,求a = sum(流向它的下界流)-sum(从它流出的下界流量)
(2)添加一条从汇点t到源点s,流量为INF的边
(3)对所有的点,根据该a值( a = sum(流向它的下界流)-sum(从它流出的下界流量) )向新构造出的源点SS,汇点TT加边
若a>0,从新源点SS连一条到i的容量为a的边
若a<0,从i连一条到新汇点TT的容量为-a的边
(4)求一次从(SS->TT)的最大流,看从SS出发的边是否全部满流,若不满流则无解
(5)删掉SS、TT这两个点
(6)再做一次(s->t)的最大流,此时各条边上的流量flow+该边的流量下限就是整个网络流量有解时的真实流量
题目:ZOJ 3229
代码:
1 #include <iostream> 2 #include <cstdio> 3 #include <vector> 4 #include <cstring> 5 #include <queue> 6 #include <algorithm> 7 #define maxn 1400 8 #define INF 1000000000 9 using namespace std; 10 int g[1010],c[400],D[400]; 11 int L[400][1010],R[400][1010],T[400][1000],task[400]; 12 int in[maxn]; 13 struct Edge{ 14 int from,to,cap,flow; 15 }; 16 17 struct ISAP { 18 int n, m, s, t; 19 vector<Edge> edges; 20 vector<int> G[maxn]; 21 bool vis[maxn]; 22 int d[maxn]; 23 int cur[maxn]; 24 int p[maxn]; 25 int num[maxn]; 26 27 void AddEdge(int from, int to, int cap) { 28 edges.push_back((Edge){from, to, cap, 0}); 29 edges.push_back((Edge){to, from, 0, 0}); 30 m = edges.size(); 31 G[from].push_back(m-2); 32 G[to].push_back(m-1); 33 } 34 35 bool BFS() { 36 memset(vis, 0, sizeof(vis)); 37 queue<int> Q; 38 Q.push(t); 39 vis[t] = 1; 40 d[t] = 0; 41 while(!Q.empty()) { 42 int x = Q.front(); Q.pop(); 43 for(int i = 0; i < G[x].size(); i++) { 44 Edge& e = edges[G[x][i]^1]; 45 if(!vis[e.from] && e.cap > e.flow) { 46 vis[e.from] = 1; 47 d[e.from] = d[x] + 1; 48 Q.push(e.from); 49 } 50 } 51 } 52 return vis[s]; 53 } 54 55 void ClearAll(int n) { 56 this->n = n; 57 for(int i = 0; i < n; i++) G[i].clear(); 58 edges.clear(); 59 } 60 61 int Augment() { 62 int x = t, a = INF; 63 while(x != s) { 64 Edge& e = edges[p[x]]; 65 a = min(a, e.cap-e.flow); 66 x = edges[p[x]].from; 67 } 68 x = t; 69 while(x != s) { 70 edges[p[x]].flow += a; 71 edges[p[x]^1].flow -= a; 72 x = edges[p[x]].from; 73 } 74 return a; 75 } 76 77 int Maxflow(int s, int t) { 78 this->s = s; this->t = t; 79 int flow = 0; 80 BFS(); 81 memset(num, 0, sizeof(num)); 82 for(int i = 0; i < n; i++) num[d[i]]++; 83 int x = s; 84 memset(cur, 0, sizeof(cur)); 85 while(d[s] < n) { 86 if(x == t) { 87 flow += Augment(); 88 x = s; 89 } 90 int ok = 0; 91 for(int i = cur[x]; i < G[x].size(); i++) { 92 Edge& e = edges[G[x][i]]; 93 if(e.cap > e.flow && d[x] == d[e.to] + 1) { // Advance 94 ok = 1; 95 p[e.to] = G[x][i]; 96 cur[x] = i; 97 x = e.to; 98 break; 99 } 100 } 101 if(!ok) { // Retreat 102 int m = n-1; 103 for(int i = 0; i < G[x].size(); i++) { 104 Edge& e = edges[G[x][i]]; 105 if(e.cap > e.flow) m = min(m, d[e.to]); 106 } 107 if(--num[d[x]] == 0) break; 108 num[d[x] = m+1]++; 109 cur[x] = 0; 110 if(x != s) x = edges[p[x]].from; 111 } 112 } 113 return flow; 114 } 115 }; 116 117 ISAP sap; 118 int main() 119 { 120 int n,m; 121 while(scanf("%d%d",&n,&m) == 2){ 122 sap.ClearAll(n+m+5); 123 memset(in,0,sizeof(in)); 124 for(int i = 1;i <= m;i++) 125 scanf("%d",&g[i]); 126 for(int day = 1;day <= n;day++){ 127 scanf("%d%d",&task[day],&D[day]); 128 for(int i = 1;i <= task[day];i++){ 129 int girl_num,l,r; 130 scanf("%d%d%d",&girl_num,&l,&r); 131 girl_num++; 132 T[day][i] = girl_num; 133 L[day][girl_num] = l; 134 R[day][girl_num] = r; 135 } 136 } 137 int s = 0,t = n+m+1; 138 int SS = t+1,TT = SS + 1; 139 for(int i = 1;i <= n;i++){ 140 for(int j = 1;j <= task[i];j++){ 141 int girl_num = T[i][j]; 142 in[i] -= L[i][girl_num]; 143 in[n+girl_num] += L[i][girl_num]; 144 sap.AddEdge(i,n+girl_num,R[i][girl_num]-L[i][girl_num]); 145 } 146 } 147 for(int i = 1;i <= n;i++){ 148 sap.AddEdge(s,i,D[i]); 149 } 150 for(int i = 1;i <= m;i++){ 151 in[n+i] -= g[i]; 152 in[t] += g[i]; 153 sap.AddEdge(n+i,t,INF-g[i]); 154 } 155 sap.AddEdge(t,s,INF); 156 int sum = 0; 157 int tmp = sap.edges.size(); 158 for(int i = 0;i <= n+m+1;i++){ 159 if(in[i] > 0) sap.AddEdge(SS,i,in[i]); 160 if(in[i] < 0) sap.AddEdge(i,TT,-in[i]); 161 if(in[i] > 0) sum += in[i]; 162 } 163 int maxflow = sap.Maxflow(SS,TT); 164 if(maxflow != sum){ 165 printf("-1 "); 166 continue; 167 } 168 for(int i = tmp;i < sap.edges.size();i++){ 169 sap.edges[i].flow = sap.edges[i].cap = 0; 170 } 171 maxflow = sap.Maxflow(s,t); 172 printf("%d ",maxflow); 173 int cnt = 0; 174 for(int i = 1;i <= n;i++){ 175 for(int j = 1;j <= task[i];j++){ 176 printf("%d ",sap.edges[cnt*2].flow+L[i][T[i][j]]); 177 cnt++; 178 } 179 } 180 printf(" "); 181 } 182 return 0; 183 }
3.有源汇有下界的最小流问题
(1)如2中的(1)(3),构造网络………………
(2)这时不能直接添加一条从汇点t到源点s,流量为INF的边!要先求一次(SS->TT)的最大流,求得最大流maxflow记为flow1
(3)添加一条从汇点t到源点s,流量为INF的边
(4)再求一次从(SS->TT)的最大流,求得最大流maxflow记为flow2
(5)假如flow1+flow2==sum(sum就是所有a>0的点的a值的和,就是SS满流情况),有解
(6)此时,最小流就是t->s边上的流量
题目:HDU 3157
代码:
1 #include <iostream> 2 #include <cstdio> 3 #include <cstring> 4 #include <vector> 5 #include <queue> 6 #include <algorithm> 7 #define maxn 60 8 #define INF 1000000000 9 using namespace std; 10 struct Edge{ 11 int from,to,cap,flow; 12 }; 13 struct Dinic{ 14 int n,m,s,t; 15 vector<Edge> edges; 16 vector<int> G[maxn]; 17 bool vis[maxn]; 18 int d[maxn]; 19 int cur[maxn]; 20 void ClearAll(int n){ 21 for(int i = 0;i < n;i++) G[i].clear(); 22 edges.clear(); 23 } 24 void AddEdge(int from,int to,int cap){ 25 edges.push_back((Edge){from,to,cap,0}); 26 edges.push_back((Edge){to,from,0,0}); 27 m = edges.size(); 28 G[from].push_back(m-2); 29 G[to].push_back(m-1); 30 } 31 bool BFS(){ 32 memset(vis,0,sizeof(vis)); 33 queue<int> Q; 34 Q.push(s); 35 vis[s] = 1; 36 d[s] = 0; 37 while(!Q.empty()){ 38 int x = Q.front();Q.pop(); 39 for(int i = 0;i < G[x].size();i++){ 40 Edge& e = edges[G[x][i]]; 41 if(!vis[e.to] && e.cap > e.flow){ 42 vis[e.to] = 1; 43 d[e.to] = d[x] + 1; 44 Q.push(e.to); 45 } 46 } 47 } 48 return vis[t]; 49 } 50 int DFS(int x,int a){ 51 if(x == t || a == 0) return a; 52 int flow = 0,f; 53 for(int& i = cur[x];i < G[x].size();i++){ 54 Edge& e = edges[G[x][i]]; 55 if(d[x] + 1 == d[e.to] && (f = DFS(e.to,min(a,e.cap-e.flow))) > 0){ 56 e.flow += f; 57 edges[G[x][i]^1].flow -= f; 58 flow += f; 59 a -= f; 60 if(a == 0) break; 61 } 62 } 63 return flow; 64 } 65 int Maxflow(int s,int t){ 66 this->s = s;this->t = t; 67 int flow = 0; 68 while(BFS()){ 69 memset(cur,0,sizeof(cur)); 70 flow += DFS(s,INF); 71 } 72 return flow; 73 } 74 }; 75 Dinic g; 76 int in[maxn]; 77 int main() 78 { 79 int n,m,s,t,SS,TT,a,b,cir; 80 char from[10],to[10]; 81 while(scanf("%d%d",&n,&m),n+m){ 82 memset(in,0,sizeof(in)); 83 g.ClearAll(n+5); 84 s = 0,t = n+1,SS = t+1,TT = SS+1; 85 int sum = 0; 86 for(int i = 0;i < m;i++){ 87 scanf("%s%s%d",from,to,&cir); 88 if(from[0] == '+') a = s; 89 else sscanf(from,"%d",&a); 90 if(to[0] == '-') b = t; 91 else sscanf(to,"%d",&b); 92 in[a] -= cir;in[b] += cir; 93 g.AddEdge(a,b,INF-cir); 94 } 95 for(int i = 0;i <= t;i++){ 96 if(in[i] > 0) g.AddEdge(SS,i,in[i]),sum += in[i]; 97 if(in[i] < 0) g.AddEdge(i,TT,-in[i]); 98 } 99 100 int flow1 = g.Maxflow(SS,TT); 101 g.AddEdge(t,s,INF); 102 int flow2 = g.Maxflow(SS,TT); 103 if(flow1 + flow2 != sum) printf("impossible "); 104 else{ 105 int e = g.edges.size() - 2; 106 printf("%d ",g.edges[e].flow); 107 } 108 } 109 return 0; 110 }