最大流HDU3549

请加我的微信公众号YWQKirin

最大流问题描述:

        在一个有容量限制的网络中,当传送流量时,如何充分利用整个拓扑网络使源点S到汇点T的流量最大。

最大流的特性:

1.网络中只有一个源点和一个汇点,如果有多个或者没有,则构造一个超级源点S和一个超级汇点T出来满足要求。

2.网络是有向网络,如果是无向网络或者混合网络,应该转化成有向网络。

3.网络中的各条弧都有一个权值。

FordFokson算法:

      核心思想:通过引进剩余网络,增光路等概念。把问题转化为给一个初值,不断的递增流量,直到达到最优解。每次找到一个增光路,路径的流量必定存在,这样迭代下去总会找到最大流量。

 时间复杂度:

        因为每次找增光路的复杂度是O(m),而网络中的最大流量不超过是(n-1U。几最终复杂度是O(nmU)。

对于HDU3549采用邻接矩阵的代码如下:

#include <stdio.h>
#include <string.h>
#include <iostream>
using namespace std;

const int MN=50;//最大的顶点数
const int INF=0x3fffffff;
//N顶点数,M边数,SS源点,TT汇点
int N,M,SS,TT;
struct Node
{
	int c,f;//c是容量,f是流量
}edge[MN][MN];
//pre是记录搜索路径时记录前一个节点的。
//vis是标记搜索过程中那些节点被搜索到
//que队列
int pre[MN],vis[MN],que[MN],qs,qe;
bool BFS()
{	
	int u,i;
	memset(pre,-1,sizeof(pre));memset(vis,0,sizeof(vis));
	qs=0;qe=0;      que[qe++]=SS;
	while(qs<qe)
	{
		u=que[qs++];
		if(u==TT) return 1;
		//可能要改i<=TT,这里要看自己怎么建图,这里假设汇点是顶点号最大
		for(i=1;i<=TT;i++)//遍历与u相邻的所有顶点
		{
			if(0x00==vis[i])
			{
				if(edge[u][i].c>edge[u][i].f)//正向流量 可以扩展
				{
					vis[i]=1; que[qe++]=i;
					pre[i]=u;
				}
				else if(edge[i][u].f>0)//反向流量 可以扩展
				{
					vis[i]=1; que[qe++]=i;
					pre[i]=u;
				}
			}
		}
	}
	return 0;
}
int max_flow()
{
	int u,mn,ans=0;
	while(BFS()) //用BFS去搜索一条增广路
	{
		mn=INF;
		for(u=TT;u!=SS;u=pre[u])//找当前路径上最小的流量
		{
			if(edge[pre[u]][u].c>edge[pre[u]][u].f)//是正向流量
			{
				if(mn>edge[pre[u]][u].c-edge[pre[u]][u].f)
					mn=edge[pre[u]][u].c-edge[pre[u]][u].f;
			}
			else if(edge[u][pre[u]].f>0)//是反向流量
			{
				if(mn>edge[u][pre[u]].f)
					mn=edge[u][pre[u]].f;
			}
		}
		for(u=TT;u!=SS;u=pre[u])//更新当前路径上的流量
		{
			if(edge[pre[u]][u].c>edge[pre[u]][u].f)
			{
				edge[pre[u]][u].f+=mn;
			}
			else if(edge[u][pre[u]].f>0)
			{
				edge[u][pre[u]].f-=mn;
			}
		}
		ans+=mn;
	}
	return ans;
}
void Read_Build()
{
    int i,u,v,c;
	scanf("%d%d",&N,&M); 
	memset(edge,0,sizeof(edge));//一定要初始化
    for(i=0;i<M;i++)
    {
        scanf("%d%d%d",&u,&v,&c);
		edge[u][v].c+=c;
    }
    SS=1;TT=N;
}
int main()
{
	int test,cas=1;scanf("%d",&test);
    while(test--)
    {
        Read_Build();
        printf("Case %d: %d\n",cas++,max_flow());
    }
	return 0;
}


 

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值