网络流详解(2)

例题是hdu 1532,一道网络流模板题,可以给大家练练手。
http://acm.hdu.edu.cn/showproblem.php?pid=1532
#include<stdio.h>
#include<string.h>
#define MAX 202
#define INF 999999999

bool bfs( int M );
void up_date( int k );
int  Min( int a , int b ){ return a < b ? a : b ; }

int min;
int rest[MAX][MAX] , pre[MAX];
//rest[i][j]表示i点到j点是否可灌水(非零就表示可灌)
//pre[k]表示BFS寻找增广路径时k的前驱

int main( ){
    int N , M , sum;
    int i , j , a , b , c ;

    while( ~scanf("%d%d",&N,&M) ){
memset( rest , 0 , sizeof( rest ) );    //开始前rest为0,即没有管道,不可灌水

for( sum=0 , i=1 ; i<=N ; i++ ){
scanf("%d%d%d",&a,&b,&c);
rest[a][b] += c ;    //处理重边情况
}

while( bfs( M ) ){
min = INF;    //min为全局变量
up_date( M );
sum += min;
}

printf("%d/n",sum);
    }

    return 0;
}


bool  bfs( int M ){
    bool mark[MAX];
    int  queue[MAX] , top , rear;
    int  s , k ;

    top = rear = 0;
    memset( mark , false , sizeof( mark ) );

    queue[rear++] = 1;    //从源点开始搜索
    mark[1] = true;

    while( top!=rear ){
s = queue[top++];

if( s==M ){    //BFS搜到了汇点
return true;
	}

for( k=1 ; k<=M ; k++ ){
if( !mark[k] && rest[s][k] ){    //rest[i][j]不为零的时候可表示正向或反向边
    mark[k] = true;
    queue[rear++] = k;    //加入队列
    pre[k] = s;    //记录前驱
		}
	}
    }
    return false;
}


void up_date( int k ){    //更新每根管道的值(看做双向管道)
    if( k==1 )    //递归达到深度
return ;

    int s=pre[k];

    min = Min( min , rest[s][k] );    //正向边负向边统一处理

    up_date( s );    //递归到最深状态

    rest[s][k] += min;    //正向管道加去min值
    rest[k][s] -= min;    //负向管道减上min值(反向管道少了的水量被正向管道使用,即实现了"隐含"双向管道)
}

//原版主在这里正向管道是减去min值,负向管道是加上了min值,但是我转载的时候改了,如果有错,希望各位神犇指出,谢谢了!(我也是正在看网络流最大流,所以想分享给同我一样的蒻苣。。。
算法分析:题目意思很明确,是求网络流中的最大流问题,该问题我采用了Fold-Fulkerson(福特-福克森)算法,算法分为两个部分,求增广路径和更新路径值,增广路经就是有向图中的源点到汇点的路径中所有正向边流量<最大流量;负向边中流量>0则称该路径为增广路径;算法求出增广路径上的权值最小值(管道剩余排水量),该路径可用增加这么多的排水量.依次执行算法到找不到增广路经为止.注意:增广路虽然是源点到汇点的一条路径,不过不能首先dfs一次性找出所有路径,因为在每次更新的时候可能其他某些路径已经不是增广路径了.该算法中rest[正]+=min,rest[负]-=min,bfs中的判断if( !mark[k] && rest[s][k] )隐含的给出了图已经被转化为双向图了(虽然从输入里看不出).

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值