标签:
Description:
Input:
Output:
Sample Input:
5 4 1 2 40 1 4 20 2 4 20 2 3 30 3 4 10
Sample Output:
50
题意:现在有m条渠道,n个渠道可以到达的点,以及每条渠道所能运输水的最大流量,同一条渠道可能有不同的流量,第1个点为水的源点,第n个点为水的汇点,现在问从源点到汇点的最低流量是多少。
1.Edmonds-Karp 最短增广路算法:
#include<stdio.h> #include<queue> #include<string.h> #include<algorithm> #define INF 0x3f3f3f3f #define N 210 using namespace std; int G[N][N], f[N]; int n; int BFS(int Start, int End) //查找能否从源点到达汇点 { int i, u; memset(f, 0, sizeof(f)); //f数组保存一条渠道的始点 queue<int>Q; Q.push(Start); while (!Q.empty()) { u = Q.front(); Q.pop(); if (u == End) return 1; for (i = 1; i <= n; i++) { if (G[u][i] && !f[i]) //如果该渠道还有流量,且还未遍历该点 { Q.push(i); f[i] = u; //让其父节点为该渠道的始点,便于添加反边 } } } return 0; } int EK(int Start, int End) { int Max = 0, Min, i; while (BFS(Start, End)) //一直查找到不能到达汇点 { Min = INF; for (i = End; i != Start; i = f[i]) Min = min(Min, G[f[i]][i]); //计算每一次的路径所能达到的最大流量(取决于每段路径流量最少的那个) for (i = End; i != Start; i = f[i]) { G[f[i]][i] -= Min; G[i][f[i]] += Min; //添加反边 } Max += Min; } return Max; //保存流到汇点的最大流量 } int main () { int m, a, b, c, ans; while (scanf("%d%d", &m, &n) != EOF) { memset(G, 0, sizeof(G)); while (m--) { scanf("%d%d%d", &a, &b, &c); G[a][b] += c; //可能存在重复渠道的情况,需要将最大流量加起来,这样才能保证流到汇点的流量最大 } ans = EK(1, n); printf("%d\n", ans); } return 0; }
2.Dinic 快速网络流算法:
#include<stdio.h> #include<queue> #include<string.h> #include<algorithm> using namespace std; const int INF=0x3f3f3f3f; const int N=210; int G[N][N], layer[N], n; //layer数组保存的是该点在进行BFS搜索时在第几层 int BFS(int Start, int End) { int i, u; memset(layer, -1, sizeof(layer)); //每次查询时都重新构图了,所以每次都需要初始化 queue<int>Q; Q.push(Start); layer[Start] = 1; //让源点为第一层 while (!Q.empty()) { u = Q.front(); Q.pop(); if (u == n) return 1; //此时已经达到汇点,可以不用再继续查找 for (i = 1; i <= n; i++) { if (layer[i] == -1 && G[u][i]) //要是该点还未遍历且有最大流量,此时该点层数+1 { layer[i] = layer[u]+1; Q.push(i); } } } return 0; } int DFS(int u, int mini) { int i, ans; if (u == n) return mini; //如果该点为汇点,说明这条路径的最小值已经找到 for (i = 1; i <= n; i++) { if (G[u][i] && layer[i] == layer[u]+1 && (ans = DFS(i, min(mini, G[u][i])))) //ans的值肯定不会是0,是最终这条路径上的最小值 { G[u][i] -= ans; //因为ans=0时说明该点不能达到汇点,回溯到for循坏,只有能达到汇点才能回溯到这里,而此时ans就是最小值 G[i][u] += ans; //增加反边 return ans; } } return 0; } int Dinic(int Start, int End) { int ans = 0, num; while (BFS(Start, End)) //一直到不能达到汇点为止 { while (1) { num = DFS(1, INF); if (num == 0) break; //等于0说明不能到达汇点 ans += num; //将每次重新构图后的最小值相加 } } return ans; //得到最大流量 } int main () { int m, a, b, c, ans; while (scanf("%d%d", &m, &n) != EOF) { memset(G, 0, sizeof(G)); while (m--) { scanf("%d%d%d", &a, &b, &c); G[a][b] += c; //防止有重边 } ans = Dinic(1, n); printf("%d\n", ans); } return 0; }
POJ 1273 Drainage Ditches(网络流模板)
标签:
原文地址:http://www.cnblogs.com/syhandll/p/4724507.html