最大网络流spa模板 优化的额

http://acm.nbut.cn/Problem/view.xhtml?id=1406

  • [1406] Bridge And Island Again

  • 时间限制: 1000 ms 内存限制: 65535 K
  • 问题描述
  • In order to strengthen the communication between the island, the government wants to convey goods from first island to Nth island. Now give you some bridges that can bear the maximum weight of goods.
    Can you calculate the maximum weight of goods that first island can convey at one time.

  • 输入
  • Input until EOF.
    First line will give you two integers N (4 <= N <= 100)(the id of islands are from 1 to N) and M (N - 1 <= M <= N * (N - 1) / 2), N means the number of islands, M means the number of bridges have be built.
    Next M lines, each line contains three integers x, y, and c (0 < c < 100), means there exists the maximum bear c from x to y (The maximum bear from x to y may be different from the maximum bear from y to x).
    For data.in, there may exist two bridges between two islands, and all islands will be linked by bridges.
  • 输出
  • Print the answer.
  • 样例输入
  • 4 6
    1 2 1
    1 3 1
    1 4 1
    2 3 2
    2 4 2
    3 4 2
    
  • 样例输出
  • 3
    
  • 提示
  • 来源
  • Hungar
题意:

输入 n m  表示n个点   之后输入m条 x y z  表示 从x到y允许通过的最大值为z    问 从起点1 到终点n能够传输的最大网络流是多少


#include <stdio.h>  
#include <string.h>  
#define INF 999999999
#define MAXN 301  
int map[MAXN][MAXN];
int SAP(int v_count,int s,int t)      //邻接矩阵,节点总数,始点,汇点  
{  
	int i;  
	int cur_flow,max_flow,cur,min_label,temp;         //当前流,最大流,当前节点,最小标号,临时变量  
	char flag;                                        //标志当前是否有可行流  
	int cur_arc[MAXN],label[MAXN],neck[MAXN];         //当前弧,标号,瓶颈边的入点(姑且这么叫吧)  
	int label_count[MAXN],back_up[MAXN],pre[MAXN];    //标号为i节点的数量,cur_flow的纪录,当前流路径中前驱  
	
	//初始化  
	memset(label,0,MAXN*sizeof(int));  
	memset(label_count,0,MAXN*sizeof(int));  
	
	memset(cur_arc,0,MAXN*sizeof(int));  
	label_count[0]=v_count;                           //全部初始化为距离为0  
	
	neck[s]=s;  
	max_flow=0;  
	cur=s;  
	cur_flow=INF;  
	
	//循环代替递归  
	while(label[s]<v_count)  
	{  
		back_up[cur]=cur_flow;  
		flag=0;  
		
		//选择允许路径(此处还可用邻接表优化)  
		for(i=cur_arc[cur];i<v_count;i++)    //当前弧优化  
		{  
			if(map[cur][i]!=0&&label[cur]==label[i]+1)    //找到允许路径  
			{  
				flag=1;  
				cur_arc[cur]=i;    //更新当前弧  
				if(map[cur][i]<cur_flow)    //更新当前流  
				{  
					cur_flow=map[cur][i];  
					neck[i]=cur;     //瓶颈为当前节点  
				}  
				else  
				{  
					neck[i]=neck[cur];     //瓶颈相对前驱节点不变  
				}  
				pre[i]=cur;    //记录前驱  
				cur=i;  
				if(i==t)    //找到可行流  
				{  
					max_flow+=cur_flow;    //更新最大流  
					
					//修改残量网络  
					while(cur!=s)  
					{  
						if(map[pre[cur]][cur]!=INF)map[pre[cur]][cur]-=cur_flow;  
						back_up[cur] -= cur_flow;  
						if(map[cur][pre[cur]]!=INF)map[cur][pre[cur]]+=cur_flow;  
						cur=pre[cur];  
					}  
					
					//优化,瓶颈之后的节点出栈  
					cur=neck[t];  
					cur_flow=back_up[cur];   
				}  
				break;  
			}  
		}  
		if(flag)continue;  
		
		min_label=v_count-1;    //初始化min_label为节点总数-1  
		
		//找到相邻的标号最小的节点     
		for(i=0;i<v_count;i++)  
		{  
			if(map[cur][i]!=0&&label[i]<min_label)  
			{  
				min_label=label[i];  
				temp=i;  
			}  
		}  
		cur_arc[cur]=temp;    //记录当前弧,下次从提供最小标号的节点开始搜索  
		label_count[label[cur]]--;    //修改标号纪录  
		if(label_count[label[cur]]==0)break;    //GAP优化  
		label[cur]=min_label+1;    //修改当前节点标号  
		label_count[label[cur]]++;     //修改标号记录  
		if(cur!=s)  
		{  
			//从栈中弹出一个节点  
			cur=pre[cur];  
			cur_flow=back_up[cur];  
		}  
	}  
	return(max_flow);  
}
int main()
{
	int m,x,y,z,n,s,t;	
	while(scanf("%d%d",&n,&m)!=EOF)
	{
		memset(map,0,sizeof(map));
		for (int i=1; i<=m; i++)
		{
			scanf("%d%d%d",&x,&y,&z);
			x=x-1;y=y-1;
			map[x][y]+=z;
		   /*注意 此模板点的编号为0 到n-1  如果要改成1 到 n 把上面的 x=x-1 y=y-1去掉 把下面改成s=1 t=n即可*/
		}	
		s=0; t=n-1;
		printf("%d\n",SAP(n,s,t));
	}
	return 0;
}

上面的模板 经过很多优化     spa算法算是时间复杂度比较好的了        比赛中使用这个模板极大部分网络流题目都不会超时




  • 2
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值