最大流首次体验感受——
什么是最大流呢?
从一个出发点(源点),走到一个目标点(汇点),途中可以经过若干条路,每条路有一个权值,表示这条路可以通过的最大流量。
最大流就是从源点到汇点,可以通过的最大流量。
接下来我们看一个图——
图1
这个图中,s是源点,t是汇点。期间可以经过2, 3, 4, 5, 6几个点。每条边上有两个权值,其中第一个表示当前通过这条边的流量,第二个表示这条边最大可以通过的流量。
最佳情况,即最大可以通过的流量的一种情况是这样的——
图2
但还有一种情况,同样可以达到最大流——
图3
这里得到两个结论:
1. 每条路径中都有至少一条边是满的。
2. 最大流可能不止一种情况。
接下来我们再看另一个图:
图4
如果在这个图上找最大流该怎么找?
这样?
图5
不对,这个图乍一看好像满足每条路径上都有一个满流的边这个条件,但是其实还有更大的流——
图6
怎么办呢?
我们可以通过这个方式从图5变到图6——
图7
这里我们的可以这样理解,在我们走出图5 的结果以后,我们允许图中出现图7中的绿色的边,然后我们就得到了绿色的数字所标示出的一条新路,通过这条路径,我们就获得了最大流。
如果我们获得了一个流量图,这个流量图中每条路径上都有一条边是满流了,如何判断这是不是一个最大流的图呢?通过上面的方法,我们在通过某条边之后,在这两个点之间构造一条反向的并且和通过的流量大小相同的边(称为反向边)。这样,就可能产生一条新路,使整个图中的流量增加。那么,我们不断地构造这种边,直到无法寻找到新的路径为止(称为增广路径),是不是就得到了最大流呢?
总结起来,每次找到一条增广路,增广路中每条边的值,都减去路径中,边值最小的边的值(读起来很凹口是不是?多读几遍就好了)。同时,还要给每条边都加上反向边。重复寻找,直到找不到新的路径,我们就获得了这个图的最大流。
注意,
- 每次寻找增广路径后,我们都会将原图更改,这样,我们会得到一个新的图。
- 在获得最大流的图之前,我们获得的每张图都称为残余网络。原始图也可以视为残余网络。
以上讲的是寻找最大流的思想。
但是,寻找增广路径的方法不止一种。
我最直接想到的方法,使用dfs多次搜索这张图,直到找不到为止。
1 #include <cstdio> 2 #include <cmath> 3 #include <cstring> 4 #include <algorithm> 5 using namespace std; 6 7 const int N = 210; 8 const int M = 10000010; 9 10 int n, m; 11 int mp[N][N]; //保存地图信息,有向图 12 bool vis[N][N]; //dfs时标记使用 13 int ans; //最终结果 14 15 void init() 16 { 17 memset(mp, 0, sizeof(mp)); 18 memset(vis, 0, sizeof(vis)); 19 for(int i = 0; i < n; i++) 20 { 21 int a, b, c; 22 scanf("%d%d%d", &a, &b, &c); 23 mp[a][b] += c; 24 } 25 ans = 0; 26 } 27 28 int dfs(int x, int maxn) 29 { 30 if(x == m) 31 { 32 ans += maxn; //每次走到汇点后增加的流量 33 return maxn; 34 } 35 int flow = 0; 36 for(int i = 1; i <= m; i++) 37 { 38 if(mp[x][i] > 0 && !vis[x][i]) 39 { 40 vis[x][i] = 1; 41 int mmaxn = maxn < mp[x][i] ? maxn : mp[x][i]; //取本路径中所可以通过的最小值 42 int mid; 43 if(mmaxn > 0) mid = dfs(i, mmaxn); //如果此路仍然是通路,则继续搜索 44 if(mid > 0) 45 { 46 mp[x][i] -= mid; //已经经过的路要减去耗费的流量 47 mp[i][x] += mid; //反向路(弧)增加耗费的流量 48 maxn -= mid; //走过一条通路后剩余的流量 49 flow += mid; //已经消耗的流量 50 if(maxn == 0) break; 51 } 52 } 53 } 54 return flow; 55 } 56 57 int main() 58 { 59 //freopen("test.in", "r", stdin); 60 while(~scanf("%d%d", &n, &m)) 61 { 62 init(); 63 while(dfs(1, M) > 0) memset(vis, 0, sizeof(vis)); 64 printf("%d\n", ans); 65 } 66 return 0; 67 }