最大网络流 EK 算法
网络流是什么类型的问题,看一道题目你就知道了 点击打开链接 。
默认具备图论的基本知识,网络流概念比较多,先看看书熟悉一下那些概念。比较好!一个寄出的网络最大流。EK算法写的。
这是一幅网络,求S ------> T 点的最大网络流。 这是初始状态。{a,b} a 代表该边的最大流量,b代表实际的流量。
一开始,实际流量为0;下面是代码。
<pre name="code" class="cpp">#include <cstdio> #include <cstring> #include <cctype> #include <cmath> #include <set> #include <map> #include <list> #include <queue> #include <deque> #include <stack> #include <string> #include <bitset> #include <vector> #include <iostream> #include <algorithm> #include <stdlib.h> using namespace std; typedef long long LL; const int INF=2e9+1e8; const int MOD=1e9+7; const int MM=250; const double eps=0.0000000001; struct Node { int c,f; }; Node edge[MM][MM]; int n,m,pre[MM]; bool bfs(int s,int t) { bool vis[MM]; memset(vis,0,sizeof(vis)); memset(pre,-1,sizeof(pre)); queue<int>q; q.push(s); vis[s]=true; while(!q.empty()) { s=q.front(); q.pop(); for(int i=1; i<=m; i++) { if(!vis[i]&&edge[s][i].c>abs(edge[s][i].f)) { vis[i]=true; pre[i]=s; if(i==t) return true; q.push(i); } } } return false; } void print(stack<int>& a)//打印路径 { cout<<"1"; while(!a.empty()) { cout<<"->"<<a.top(); a.pop(); } cout<<endl; } int solve() { int maxflow=0; while(true) { if(!bfs(1,m)) return maxflow; int flow=INF; stack<int>s; for(int x=m,y=pre[m]; y!=-1; x=y,y=pre[y]) { flow=min(flow,edge[y][x].c-edge[y][x].f); s.push(x); } // print(s); for(int x=m,y=pre[m]; y!=-1; x=y,y=pre[y]) { edge[y][x].f+=flow; edge[x][y].f-=flow; } maxflow+=flow; } } int main() { while(cin>>n>>m) { memset(edge,0,sizeof(edge)); for(int i=0; i<n; i++) { int s,t,val; cin>>s>>t>>val; edge[s][t].c+=val; } printf("%d\n",solve()); } return 0; } /* _ooOoo_ o8888888o 88" . "88 (| -_- |) O\ = /O ____/`---'\____ .' \\| |// `. / \\||| : |||// \ / _||||| -:- |||||- \ | | \\\ - /// | | | \_| ''\---/'' | | \ .-\__ `-` ___/-. / ___`. .' /--.--\ `. . __ ."" '< `.___\_<|>_/___.' >'"". | | : `- \`.;`\ _ /`;.`/ - ` : | | \ \ `-. \_ __\ /__ _/ .-` / / ======`-.____`-.___\_____/___.-`____.-'====== `=---=' ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ The program have no BUG. */
该算法的大致思路是:不断的找寻s到t的可行流。直到找不到为止。每次找到都要之后改变该路径上的实际流量。
用广搜来寻找路径。
比如第一次找到的路径是 S → 1 →2 →T;增加流量为4
把实际流量更新后得到
再找 S→1→4→T
这条路上S到1只剩下1 所以增加的流量为1 便得到
再找 S→3→4→1
可以增加的流量为 4 ,便得到
下一次将不会找到再可以增加流量的路径。所以程序结束,增加流量为 4+1+4;所以最大流为9;
不过还有一种情况:
从肉眼来看很容易 S→1→2→T 加 S→3→4→T 得到15;
但是计算机执行有可能会首选 S→1→4→T。便得到 再选择 S→1→2→T得到右图
就再搜不到其他的了但是得到的确实10;说明这样作并不是最优的。所以EK算法提供了一种后悔的机制。正向流量加的同时,反向容量也同时加。这样就相当于 让刚刚流经1到4的让他从1→2→T 我从 4→T
1与4 这条边,一开始是从1到4流过5,反方的流量就变为5;当另一个流经 S,3,4 时 就可以走1,2,T 。合起来就是
S→3→4→1→2→T 又增加流量为5 到最后 E<1,4> 这条边总流量为 0;这种机制刚好解决了这个问题。
OVER