最大流(EK模版)——HDOJ 3549

HDOJ 3549 Flow Problem

这道题目可以作为最大流算法的模版,也是最简单的最大流题目之一

/*
HDOJ 3549 Flow Problem
最大流,第一道题目,纯粹是理解EK算法
*/

#include <iostream>
#include <queue>
using namespace std;

#define min(a,b) (a)<(b)?a:b
#define N 16
int capacity[N][N]; //容量
int flow[N]; //残余容量
int pre[N]; //前驱结点
int n,m;
queue<int> qu;

int BFS(int src,int des)
{
	while(!qu.empty())
		qu.pop();
	for(int i=1;i<=n;i++)
		pre[i]=-1;
	pre[src]=0;
	flow[src]=INT_MAX; //初始化源点的流量为无穷
	qu.push(src);
	while(!qu.empty())
	{
		int index=qu.front();
		qu.pop();
		if(index == des)
			break;
		for(i=1;i<=n;i++)
		{
			if(i!=src && capacity[index][i]>0 && pre[i] == -1)
			{
				pre[i]=index;
				flow[i]=min(capacity[index][i],flow[index]);
				//一步步找出增广路径中的最小的可增加流量
				qu.push(i);
			}
		}
	}
	if(pre[des] == -1)
		return -1; //不存在增广路径
	return flow[des];
}

int MaxFlow(int src,int des)
{
	int aug=0;
	int sumflow=0;
	while((aug=BFS(src,des)) != -1)
	{
		int k=des;
		while(k!=src)
		{
			int last=pre[k];
			capacity[last][k] -= aug;
			capacity[k][last] += aug;
			k=last;
		}
		sumflow += aug;
	}
	return sumflow;
}

int main()
{
	int nCase,cas=1;
	cin>>nCase;
	while(nCase--)
	{
		cin>>n>>m;
		memset(capacity,0,sizeof(capacity));
		memset(flow,0,sizeof(flow));
		for(int i=0;i<m;i++)
		{
			int u,v,w;
			cin>>u>>v>>w;
			if(u == v)
				continue;
			capacity[u][v] +=w;
		}
		cout<<"Case "<<cas++<<": "<<MaxFlow(1,n)<<endl;
	}
	return 0;
}

下面是邻接表的实现

#include <iostream>
using namespace std;

#define min(a,b) (a)<(b)?a:b
#define NV 16
#define NE 2000

struct Edge
{
	int e;
	int w;
	int next;
}edge[NE];

int head[NV];
int pre[NV];
int cur[NV];
int que[NV],front,rear;
int n,edgesum,m;

inline void init(int x)
{
	n=x;
	edgesum=0;
	for(int i=0;i<=n;i++)
		head[i]=-1;
}

inline void insert(int s,int e,int w)
{
	edge[edgesum].e=e;
	edge[edgesum].w=w;
	edge[edgesum].next=head[s];
	head[s]=edgesum++;

	edge[edgesum].e=s;
	edge[edgesum].w=0;
	edge[edgesum].next=head[e];
	head[e]=edgesum++;
}

int MaxFlow(int src,int des)
{
	int maxflow=0;
	while(1)
	{
		memset(pre,-1,sizeof(pre));
		que[front=rear=0]=src;
		while(front <= rear)
		{
			int u=que[front++];
			for(int i=head[u];i != -1;i=edge[i].next)
			{
				int e=edge[i].e;
				if(pre[e] == -1 && edge[i].w>0)
				{
					pre[e]=u;
					que[++rear]=e;
					cur[e]=i;
				}
			}
			if(pre[des] != -1)
				break; //已经找到一条增广路径
		}
		if(pre[des] == -1)
			break;
		int aug=INT_MAX;
		for(int v=des;v!=src;v=pre[v])
			aug=min(aug,edge[cur[v]].w);
		for(v=des;v!=src;v=pre[v])
		{
			edge[cur[v]].w -= aug;
			edge[cur[v]^1].w += aug;  //这里用异或运算,是因为正反两条边刚好是一前一后的
		}
		maxflow += aug;
	}
	return maxflow;
}

int main()
{
	int cas=1,nCase;
	cin>>nCase;
	while (nCase--)
	{
		cin>>n>>m;
		init(n);
		while(m--)
		{
			int u,v,w;
			cin>>u>>v>>w;
			if(u == v)
				continue;
			insert(u,v,w);
		}
		cout<<"Case "<<cas++<<": ";
		cout<<MaxFlow(1,n)<<endl;
	}
	return 0;
}


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值