标号法过程为:
(1) 先将 flag、 prev 和 alpha 这 3 个数组各元素都初始化-1 。
(2) 将源点初始化为已标号未检查顶点,即 flag[0] = 0, prev[0] = 0, alpha[0] = INF, INF 表示无穷大;并将源点入队列。
(3) 当队列非空并且汇点没有标号,从队列头取出队列头顶点,设这个顶点为 v, v 肯定是已标号未检查顶点;因此,检查顶点 v 的正向和反向“邻接”顶点,如果没有标号并当前可以进行标号,则对这些顶点进行标号并入队列,这些顶点都是已标号未检查顶点;此后顶点 v 为已标号已检查顶点。反复执行这一步直至队列为空或汇点已获得标
测试数据:(6 表示顶点数, 10表示边数!)
6 10
0 1 8 2
0 2 4 3
1 3 2 2
1 4 2 2
2 1 4 2
2 3 1 1
2 4 4 0
3 4 6 0
3 5 9 3
4 5 7 2
1 //////// 标号法求网络最大流. 2 3 #include <cstdio> 4 #include <cstring> 5 #include <cmath> 6 7 #define _clr(x, y) memset(x, y, sizeof(x)) 8 #define Min(x, y) (x < y ? x : y) 9 #define INF 0x3f3f3f3f 10 #define N 1005 11 using namespace std; 12 13 struct ArcNode // 弧结构:c表示容量,f表示流量. 14 { 15 int c, f; 16 }; 17 ArcNode edge[N][N]; 18 int queue[N]; // 队列 19 int flag[N]; // -1表示未检查未访问,0表示已访问未检查相邻顶点,1表示已访问已检查相邻顶点 20 int pre[N]; // 保存一个点的前驱. 21 int alpha[N]; //保存一个点的可改进量 22 int n; 23 24 int abs(int a) 25 { 26 return a < 0 ? -a : a; 27 } 28 29 void ford() 30 { 31 while(1) 32 { 33 // 初始化, 34 int front=0, rear=0; 35 _clr(flag, -1); 36 _clr(pre, -1); 37 _clr(alpha, -1); 38 flag[0] = 0, pre[0] = 0, alpha[0] = INF; 39 queue[rear++] = 0; // 把源点加入队列 40 while(front<rear && flag[n-1]==-1) // 队列非空 且 汇点还未标号 41 { 42 int v = queue[front++]; 43 for(int i=0; i<n; i++) // 检查顶点v的相邻顶点 44 { 45 if(flag[i]==-1) // i点还未访问 46 { 47 if(edge[v][i].c<INF && edge[v][i].f<edge[v][i].c) // 正向且流量未满 48 { 49 flag[i] = 0, pre[i] = v; 50 alpha[i] = Min(alpha[v], edge[v][i].c-edge[v][i].f); 51 queue[rear++] = i; 52 } 53 else if(edge[i][v].c<INF && edge[i][v].f) // 反向 且 有流量 54 { 55 flag[i] = 0, pre[i] = -v; 56 alpha[i] = Min(alpha[v], edge[i][v].f); 57 queue[rear++] = i; 58 } 59 } 60 } 61 flag[v] = 1; // 加上源点流出量即是 最大流! 62 } 63 64 if(flag[n-1]==-1 || alpha[n-1]==0) break; // 汇点无法标号 或 得到的可改进量为0:即没有可改进路. 65 66 // 进行调整后得到残留网络. 67 int k1=n-1, k2=abs(pre[k1]); 68 int a = alpha[n-1]; 69 while(1) 70 { 71 if(edge[k2][k1].f<INF) // 正向加上可改进量 72 edge[k2][k1].f += a; 73 else // 反向减去可改进量 74 edge[k1][k2].f -= a; 75 if(k2==0) break; // 直至到源点. 76 k1 = k2, k2 = abs(pre[k1]); 77 } 78 } 79 80 int MaxFlow=0; 81 for(int i=0; i<n; i++) 82 for(int j=0; j<n; j++) 83 if(edge[i][j].f<INF) 84 { 85 printf("%d->%d: %d ", i,j,edge[i][j].f); // 输出各条弧的实际流量 86 if(i==0) 87 MaxFlow += edge[i][j].f; // 加上源点流出量即是 最大流! 88 } 89 printf("MaxFlow: %d ", MaxFlow); 90 } 91 int main() 92 { 93 int m, a, b, c, f; 94 while(~scanf("%d%d", &n, &m)) 95 { 96 for(int i=0; i<n; i++) 97 for(int j=0; j<n; j++) 98 edge[i][j].c=edge[i][j].f = INF; 99 while(m--) 100 { 101 scanf("%d%d%d%d", &a, &b, &c, &f); 102 edge[a][b].c = c, edge[a][b].f = f; 103 } 104 puts("before test"); 105 ford(); 106 puts("after test"); 107 } 108 return 0; 109 }
transform: none; white-space: normal;
Dinic
算法的具体步骤为:
(1) 初始化容量网络和网络流;
(2) 构造残留网络和层次网络,若汇点不在层次网络中,则算法结束;
(3) 在层次网络中用一次 DFS 过程进行增广, DFS 执行完毕,该阶段的增广也执行完毕;
(4) 转步骤(2)
#include <cstdio> #include <cstring> #define _clr(x, y) memset(x, y, sizeof(x)) #define Min(x, y) (x < y ? x : y) #define INF 0x3f3f3f3f #define N 1003 using namespace std; int edge[N][N]; int queue[N], n; int dist[N]; // 建立层次图 bool bfs() { _clr(dist, -1); int front=0, rear=0; dist[1] = 0; queue[rear++] = 1; while(front < rear) { int u = queue[front++]; for(int v=1; v<=n; v++) { if(dist[v]<0 && edge[u][v]) { dist[v] = dist[u] + 1; queue[rear++] = v; } } } return dist[n]>0 ? 1:0; } // dfs代表一次增广,返回的是本次增广获得的可改进量.0表示没有增广路 int dfs(int u, int low) { int a = 0; if(u==n) return low; for(int v=1; v<=n; v++) { // u.v之间联通且满足层次条件约束且有曾广路存在 if(edge[u][v] && dist[v]==dist[u]+1 && (a = dfs(v, Min(low, edge[u][v])))) { edge[u][v] -= a; edge[v][u] += a; return a; } } return 0; } int main() { int m, a, b, c; while(~scanf("%d%d", &m, &n)) { _clr(edge, 0); while(m--) { scanf("%d%d%d", &a, &b, &c); edge[a][b] += c; } int ans=0, a=0; while(bfs()) // 一直建立层次图,直到无法到达汇点为止. while(a = dfs(1,INF)) // 得到一条曾广路的可改进量. ans += a; printf("%d ",ans); } return 0; }
一般预流推进算法
1 #include <cstdio> 2 #include <cstring> 3 #include <queue> 4 #define _clr(x, y) memset(x, y, sizeof(x)) 5 #define Min(x, y) (x < y ? x : y) 6 #define INF 0x3f3f3f3f 7 #define N 1005 8 using namespace std; 9 10 int flow[N][N], h[N]; 11 int E[N], n, MaxFlow, S, T; 12 queue<int> Q; 13 14 void Push(int &x) 15 { 16 for(int i=1; i<=n; i++) 17 { 18 int tmp = Min(E[x], flow[x][i]); 19 if(tmp>0 && (x==S || h[x]==h[i]+1)) 20 { 21 flow[x][i] -= tmp, flow[i][x] += tmp; 22 E[x] -= tmp, E[i] += tmp; 23 if(i==T) MaxFlow += tmp; 24 if(i!=T && i!=S) Q.push(i); 25 } 26 } 27 } 28 29 void Push_Relabel() 30 { 31 MaxFlow = 0; 32 S = 1, T=n; 33 _clr(h, 0); 34 _clr(E, 0); 35 E[S]=INF, E[T]=-INF; 36 h[S]=n; 37 Q.push(S); 38 while(!Q.empty()) 39 { 40 int x = Q.front(); 41 Q.pop(); 42 Push(x); 43 if(x!=S && x!=T && E[x]>0) 44 { 45 h[x]++; 46 Q.push(x); 47 } 48 } 49 printf("%d ", MaxFlow); 50 } 51 int main() 52 { 53 int m, a, b, c; 54 while(~scanf("%d%d", &m, &n)) 55 { 56 _clr(flow, 0); 57 while(m--) 58 { 59 scanf("%d%d%d", &a, &b, &c); 60 flow[a][b] += c; 61 } 62 while(!Q.empty()) Q.pop(); 63 Push_Relabel(); 64 } 65 return 0; 66 }