本题为赤裸裸的最大流模板题。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
#include
#include
#include
#include
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()
{
queueq;
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;
}