版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/qq_40924940/article/details/83479256
核心思路:
(首先感谢网络大牛代码 附大牛网址:https://blog.csdn.net/huzhengnan/article/details/7766446)
我们首先 采用搜索的方式 来找到一条从 s-t 的路径 并且储存记录剩余量,之后采用链表的方式记录下我们走的每一条路,反向回去更新路的流量(正是有了反向流量 我们在搜素的时候 才能够有一个"反悔"的机会)最终,找到重点,记录最大流。
#include<iostream>
#include<queue>
using namespace std;
const int N=201;
const int INF=99999999;
int n,m,sum;//s,t为始点和终点
int flow[N][N],cap[N][N],a[N],pre[N];
//分别为:flow[u][v]为<u,v>流量、cap[u][v]为<u,v>容量、a[i]表示源点s到节点i的路径上的残留量、pre[i]记录i的前驱
void Edmonds_Karp(int s)
{
queue<int>q;//队列,用bfs找增广路
while(1)
{
memset(a,0,sizeof(a));//每找一次,初始化一次
a[s]=INF;
q.push(s);//源点入队
int sum=0;
while(!q.empty())
{
int u=q.front();
q.pop();
for(int v=1;v<=m;v++)
{
if(!a[v]&&flow[u][v]<cap[u][v])
{
p[v]=u;
q.push(v);
a[v]=min(a[u],cap[u][v]-flow[u][v]);//s-v路径上的最小残量
}
}
}
if(a[m]==0)//找不到增广路,则当前流已经是最大流
break;
sum+=a[m];//流加上
for(i=m;i!=s;i=p[i])// //从汇点顺着这条增广路往回走
{
flow[p[i]][i]+=a[m];//更新正向流量
flow[i][p[i]]-=a[m];//更新反向流量
}
}
printf("%d\n",sum);
}
int main()
{
int v,u,w;
while(scanf("%d%d",&n,&m)!=EOF)
{
memset(flow,0,sizeof(flow));//初始化
memset(cap,0,sizeof(cap));
while(n--)
{
scanf("%d%d%d",&u,&v,&w);
cap[u][v]=w;
}
Edmonds_Karp(1);
}
return 0;
}
目前我们很愉快的解决了一个基础最大流问题,但是我们如果更加追求一下完美,让整个程序占得空间更加小一些,用的数组更加小一些,是不是会更加优秀?
那么我们的思路可以放在流量和容量这个问题上了,如果流量超过容量是不可以的,那么我们流了多少,容量就相应的减去多少,是不是就会比我们增加“流量”这个数组里的值要来的更加方便?
#include<iostream>
#include<queue>
using namespace std;
const int N=201;
const int INF=99999999;
int n,m,sum,w;//s,t为始点和终点
int cap[N][N],a[N],p[N];
void Edmonds_Karp(int s)
{
int i,u,v;
queue<int>q;//队列,用bfs找增广路
while(1)
{
memset(a,0,sizeof(a));//每找一次,初始化一次
a[s]=INF;
q.push(s);//源点入队
while(!q.empty())
{
u=q.front();
q.pop();
for(v=1;v<=m;v++)
{
if(!a[v]&&cap[u][v]>0)
{
p[v]=u;
q.push(v);
a[v]=min(a[u],cap[u][v]);//s-v路径上的最小残量
}
}
}
if(a[m]==0)//找不到增广路,则当前流已经是最大流
break;
sum+=a[m];//流加上
for(i=m;i!=s;i=p[i])// //从汇点顺着这条增广路往回走
{
cap[p[i]][i]-=a[m];//更新正向流量
cap[i][p[i]]+=a[m];//更新反向流量
}
}
printf("%d\n",sum);
}
int main()
{
int v,u;
while(scanf("%d%d",&n,&m)!=EOF)
{
sum=0;//记录最大流量
memset(cap,0,sizeof(cap));//初始化
while(n--)
{
scanf("%d%d%d",&u,&v,&w);
cap[u][v]=w;
}
Edmonds_Karp(1);
}
return 0;
}
那么就目前而看 基础的最大流算法我们已经搞得比较通透了。。但是这串代码只是个模板,还是要熟悉的运用。
总结: 最大流(用搜索实现,依靠的还有一些图论的思想,通过有向图反向地边权值来实现一种“反悔”的方法)
当然这还不是最优秀的算法。还可以先bfs对图进行分层 之后再搜索一下,会更省时间(下篇再见)