网络流最大流之Ford-Fulkerson算法

来源:互联网 发布:淘宝钱盾怎么验证 编辑:程序博客网 时间:2024/05/21 23:03

今天又重温了一下网络流

也是第一次用C语言尝试(好吧也是人生第一次,以前Pascal没试过,只是看过原理)

重新理解原理之后照着书打了一遍,改了好久才成功

后来自己重新一个人打了一遍,只犯了一个特别小特别蠢的错误,然后就调成功了

感觉代码能力也是一种能力吧,虽然说最大流在网络流题目里算基础的,但毕竟人家也是网络流,总体难度还是不低的,

打完一遍发现自己真的掌握了感觉还是不错的,感觉代码能力在不断提高,嗯,我的f'(x)>0,

嗯,就是这样,下面开始上课(默认大家都知道什么叫网络流,知道网络流的三个基础条件,什么叫最大流):

Ford-Fulkerson算法求网络流问题的最大流

核心就是找增广路

Ford-Fulkerson是最基础的一般增广路方法

如果从源点到汇点的一条链,满足所有前向弧都是非饱和弧,所有后向弧都是非零弧,那么这条链就是当前流的一条增广路

存在增广路意味着还可以找到更大的流

最大流等价于不存在增广路

存在增广路时,可以对链上每一条弧进行修改从而得到更大的流网络

修改的规则是

前向弧增加a

后向弧减小a

a是什么呢?

a是所有前向弧中残留容量的最小值与所有后向弧中当前流量最小值的较小者

说的有些拗口,

可能比较难理解,没图确实比较糟糕,下次争取弄个图出来

还是直接进入ford-fulkerson算法的思路吧

用BFS,从源点开始扩展,将扩展的点依次放入队列,并以之不断扩展,直到汇点进入队列

对每个进入队列的点x进行标号,(prev[x],alpha[x])程序中用的是p[x],a[x],

prev[x]表示x的前缀点,alpha[x]表示到当前点的a(上文所述),

这样到汇点时,就是整条链上的a了,然后根据修改规则进行调整

直到找不到增广路,于是就得到了最大流,

嗯,结束了。

附代码:

q[]是队列,bo[]判断是否扫描过,

#include<stdio.h>
#include<stdlib.h>
#include<memory.h>
#define MAXN 1000
#define INF 1000000
int n,m,sum=0;
int bo[MAXN];
int p[MAXN];
int a[MAXN];
int q[MAXN];
struct ArcType
{
int c,f;
};
ArcType edge[MAXN][MAXN];
int min(int x,int y)
{
if (x>y) return y;
else return x;
}
void ford()
{
int h,r,x,i,j;
while (1) {
memset(bo,0xff,sizeof(bo));
memset(p,0xff,sizeof(p));
memset(a,0xff,sizeof(a));
memset(q,0,sizeof(q));
bo[0]=0;p[0]=0;a[0]=INF;
h=0;r=1;q[0]=0;
while (h<r&&bo[n-1]==-1){
x=q[h];h++;
for (i=0;i<n;i++)
if (bo[i]==-1)
{
if (edge[x][i].c<INF&&edge[x][i].f<edge[x][i].c){
q[r]=i;r++;
bo[i]=0;p[i]=x;a[i]=min(a[x],edge[x][i].c-edge[x][i].f);
}
else if (edge[i][x].c<INF&&edge[i][x].f>0){
q[r]=i;r++;
bo[i]=0;p[i]=-x;a[i]=min(a[x],edge[i][x].f);
}
}
bo[x]=1;
}//寻找增广路

if (a[n-1]==0||bo[n-1]==-1) break;
int k1=n-1,k2=abs(p[k1]);
int aa=a[n-1];
while (1) {
if (edge[k2][k1].f<INF)
edge[k2][k1].f+=aa;
else edge[k1][k2].f-=aa;
if (k2==0) break;
k1=k2;k2=abs(p[k1]);
}//用来逆推回去修改流量,得到一个更大的流

}
for (j=1;j<n;j++)
if (edge[0][j].f<INF) sum+=edge[0][j].f;
printf("%d",sum);
}
int main()
{
int i,j,x,y,c,f;
scanf("%d%d",&n,&m);
for (i=0;i<n;i++)
for (j=0;j<n;j++)
edge[i][j].c=edge[i][j].f=INF;
for (i=1;i<=m;i++)
{
scanf("%d%d%d%d",&x,&y,&c,&f);
edge[x][y].c=c;edge[x][y].f=f;
}
ford();
system("pause");
return 0;
}

原创粉丝点击