最大流问题 pku 1273 Drainage Ditches

采用最短增益路径算法

题目链接:

http://acm.pku.edu.cn/JudgeOnline/problem?id=1273

 

代码注释贴上

 

 

#include <stdio.h>
#include <memory.h>

#define MAX 201
#define Inf 1<<20
#define MIN(x,y) ((x) < (y) ? (x) : (y))

int mat[MAX][MAX];
int flow[MAX][MAX];

//-------------------------------------------------------
//总结:利用队列进行广度探索,标记每个点的父结点和可再容纳的最大流量,
//探测到汇点时,汇点的可再容纳流量即是增益的流量,
//反复进行,直到不能探测到汇点为止。
//-------------------------------------------------------
//参数:节点数n,矩阵mat[][],源点source,汇点sink,每条边的流量 flow[][]
//返回:最大流 每条边的流量flow
int ford_fulkerson(int n,int mat[][MAX],int source,int sink,int flow[][MAX])
{
	//d[]用来表示还能容纳的容量
	int pre[MAX],que[MAX],d[MAX],p,q,t,i,j;
	//源点和汇点相同则返回
    if (source==sink)                                              
		return Inf;
	//初始化每条边的流量
	for (i=0;i<n;i++)                                              
		for (j=0;j<n;j++)
			flow[i][j] = 0;
		
		//反复标记,反复查找增益路径
		while(1)
		{
			//pre用来标记父结点,前驱节点,标记为0表示还为找到前驱节点
			for (i=0;i<n;i++)
				pre[i]=0;
			t= source;
			pre[source]=source+1;
			d[source]=Inf;
			//广度探索 que是用数组模拟的队列
			for (p=q=0;p<=q && !pre[sink];t=que[p++]) 
			{
				for (i=0;i<n;i++)
				{
					//前向边
					if (!pre[i] && mat[t][i]-flow[t][i] > 0){
						//i加入队列
						que[q++] = i;
						//标记第i + 1个顶点的前驱为第t + 1个顶点
						pre[i]=t+1;
						d[i] = MIN(d[t],mat[t][i] - flow[t][i]);
					}
					//后向边
					else if (!pre[i] && (j=flow[i][t]) > 0){
						que[q++]=i;
						//第i + 1个顶点的前驱为第t + 1个顶点,因为是后向边,加上-标记,整个成负数
						pre[i]=-t-1;
						d[i] = MIN(d[t],flow[i][t]);
					}
				}
			}
			//结束,不能标记汇点,也就是说不存在该条路径
			if (!pre[sink]) break;
			//回溯。。。
			//从汇点开始增加边的流量,直到源点
			for (i=sink;i!=source;)
			{
				//正向边
				if (pre[i] > 0){
					flow[pre[i]-1][i] += d[sink];
					i=pre[i]-1;
				}
				//反向边
				else{
					flow[i][-pre[i]-1] -= d[sink];
					i=-pre[i]-1;
				}
			}
		}
		//把和源点相接的边的流量相加即最大流量
		j = 0;
		for (i=0;i<n;i++)
			j+=flow[source][i];
		return j;
}

int main(){
	int N,M;
	int i;
	int S,E,C;
	//FILE *fp = fopen("max_flow.txt","r");
	while(scanf("%d%d",&N,&M)/*fscanf(fp,"%d%d",&N,&M)*/ != EOF){
		memset(mat,0,sizeof(mat));
		for(i = 0;i < N;i++){
			scanf("%d%d%d",&S,&E,&C);
			//fscanf(fp,"%d%d%d",&S,&E,&C);
			mat[S - 1][E - 1] += C;
		}
		int max_flow = ford_fulkerson(M,mat,0,M - 1,flow);
		printf("%d/n",max_flow);
	}
	return 0;
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值