2 3 2 1 2 1 2 3 1 3 3 1 2 1 2 3 1 1 3 1
Case 1: 1 Case 2: 2
本题为赤裸裸的最大流模板题。Ford-Fulkerson方法
其中为什么要用到残留网络,不好理解。
下面讲解有所启发,转载于:http://www.cnblogs.com/acSzz/archive/2012/09/13/2683820.html
必须使用反向弧的流网络
在这幅图中我们首先要增广1->2->4->6,这时可以获得一个容量为 2的流,但是如果不建立4->2反向弧的话,则无法进一步增广,最终答案为2,显然是不对的,然而如果建立了反向弧4->2,则第二次能进行 1->3->4->2->5->6的增广,最大流为3.
Comzyh对反向弧的理解可以说是"偷梁换柱",请仔细阅读: 在上面的例子中,我们可以看出,最终结果是1->2->5->6和1->2->4->6和 1->3->4->6.当增广完1->2->4->6(代号A)后,在增广 1->3->4->2->5->6(代号B),相当于将经过节点2的A流从中截流1(总共是2)走2->5>6,而不走2->4>6了,同时B流也从节点4截流出1(总共是1)走4->6而不是4->2->5->6,相当于AB流做加法.
代码:
#include <iostream> #include <algorithm> #include <stdio.h> #include <string.h> #include <queue> using namespace std; using namespace std; const int maxn=20; const int inf=0x3f3f3f3f; int pre[maxn]; //保存前驱节点 bool vis[maxn]; int mp[maxn][maxn];//临接矩阵保存残留网络 int s,e;//s为源点,e为汇点 int n,m;//输入n个顶点,m条边 bool bfs() { queue<int>q; memset(pre,0,sizeof(pre)); memset(vis,0,sizeof(vis)); vis[s]=1; q.push(s); while(!q.empty()) { int first=q.front(); q.pop(); if(first==e) return true;//找到一条增广路 for(int i=1;i<=n;i++) { if(!vis[i]&&mp[first][i]) { q.push(i); pre[i]=first; vis[i]=1; } } } return false; } int max_flow() { int ans=0; while(1) { if(!bfs())//找不到增广路 return ans; int Min=inf; for(int i=e;i!=s;i=pre[i])//回溯找最小流量 Min=min(Min,mp[pre[i]][i]); for(int i=e;i!=s;i=pre[i]) { mp[pre[i]][i]-=Min; mp[i][pre[i]]+=Min; } ans+=Min; } } int main() { int t; scanf("%d",&t); int u,v,c; for(int cas=1;cas<=t;cas++) { scanf("%d%d",&n,&m); s=1,e=n; memset(mp,0,sizeof(mp)); while(m--) { scanf("%d%d%d",&u,&v,&c); mp[u][v]+=c; } printf("Case %d: %d\n",cas,max_flow()); } return 0; }
[ACM] hdu 3549 Flow Problem (最大流模板题)
原文地址:http://blog.csdn.net/sr_19930829/article/details/39525605