此题是最大流的裸题,适合网络流初学者练习。
Edmonds_Karp 增广路径算法运行过程:
如果能找到新的增广路径则:
用广度优先搜索,不断地找边最少的增广路径,同时记录每个点的前驱;
之后求出本次增广路径的流量大小(即为路径中最短的边的容量);
然后要给路径中的边都减去本次的流量,并将每两个点之间反向加上一条等于流量的边。
#include<iostream>
#include<queue>
#include<cstring>
#include<cstdio>
using namespace std;
const int N=203;
const int inf =214748364;
int n,m,s=1,t;
int E[N][N],pre[N];//存边、记录前驱结点
bool vd[N];//记录BFS中的点是否已访问
int EK()
{
deque <int>q;//双向队列
bool FindPath=false;//记录是否可以找到一条从源点到汇点的路径
memset (vd,false,sizeof(vd));
memset (pre,0,sizeof(pre));
q.push_back(s);
pre[s]=0;//源点前驱为零
vd[s]=true;
while (q.size())//BFS搜索
{
int u=q.front();
q.pop_front();
for (int i=1;i<=m;i++)
{
if (E[u][i]>0&&vd[i]==false)
{
pre[i]=u;
vd[i]=true;
if (i==m)
{
FindPath=true;
q.clear();
break;
}
else
q.push_back(i);
}
}
}
if (!FindPath)//没有增广路径了就结束
return 0;
int MinFlow=inf,v=m;
while (pre[v])//计算出本次增广路径流量大小(即为路径中最小边流量)
{
MinFlow=min(MinFlow,E[pre[v]][v]);
v=pre[v];
}
for (int i=m;i!=s;i=pre[i])
{
E[pre[i]][i]-=MinFlow;//从汇点到源点将走过的边都减去本次增广路径的流量
E[i][pre[i]]+=MinFlow;//再反向加上本次增广路径的流量
}
return MinFlow;
}
int main()
{
while (scanf ("%d%d",&n,&m)!=EOF)// !=EOF一定要写,不然超时
{
t=m;
memset (E,0,sizeof(E));
for (int i=1;i<=n;i++)
{
int a,b,c;
scanf ("%d%d%d",&a,&b,&c);
E[a][b]+=c;//注意两节点之间有可能出现多条水渠
}
int sum=0,aug;
while (aug=EK())//若函数返回值为零,则跳出循环
sum+=aug;
printf ("%d\n",sum);
}
return 0;
}