网络流算法(1)——Improved SAP

本文详细介绍了ImprovedSAP算法的基本思想及其与Dinic算法的区别,通过具体的伪代码展示了该算法的实现过程,适用于解决最短路径增权问题。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

国内有很多OIER把Improved SAP叫做SAP,说实话这是有些不妥的。因为SAP的定义是以最短路径增值为基础的网络流算法,Dinic算法从广义上讲也是SAP算法的一种。

SAP的思想其实和Dinic很像,不过注重的是对层数标号的维护,而不是像Dinic一样用完一个层次便重新进行广搜。

其基本步骤可以概括为if(起点层次<n){

if(当前节点==n)  增广并将当前节点重设为1;

从当前节点找满足条件的边,

如果存在,则前进一步,将当前节点设为边的下一个点,并设置回路;

否则,则对当前节点进行重标号,并利用之前保存的回路回退一步;

}

代码如下

#include<iostream>
#include<cstdlib>
#include<cstdio>
#include<cstring>
#define MAXN 100000
#define INF 0xffffff
using namespace std;
struct list{
	int val,p;
	list *next,*b;
	list(){}
	list(int _p,int _val,list *_next)
	:p(_p),val(_val),next(_next){}
}T[MAXN*20],*head[MAXN],*now_head[MAXN],*data;
list *rev[MAXN];
int m,n,sum;
int L[MAXN],edge[MAXN];
void ISAP(){
	int now;
	for(int i=1;i<=n;i++) now_head[i]=head[i];
	memset(L,0,sizeof(L));
	L[0]=n;now=1;
	while(L[1]<n){
		//for(int i=1;i<=n;i++) printf("%d ",L[i]);
		//cout<<endl;system("pause");
		if(now==n){
			int delta=INF;
			for(int i=1;i!=n;i=now_head[i]->p) 
				if(now_head[i]->val>0) delta=min(delta,now_head[i]->val);
			for(int i=1;i!=n;i=now_head[i]->p)
				now_head[i]->val-=delta,now_head[i]->b->val+=delta;//增广
			sum+=delta;
			now=1;//重设当前节点
		}list *k;
		for(k=now_head[now];k;k=k->next) 
			if(k->val&&L[k->p]==L[now]-1) break;//找满足条件的边
		if(k){
			now_head[now]=k;
			rev[now=k->p]=k->b;
		}else{
			int minf=INF;
			if((--edge[L[now]])==0) break; //GAP优化,非常有效
			now_head[now]=head[now];
			for(list *s=head[now];s;s=s->next) if(s->val) minf=min(minf,L[s->p]);//重标号
			++edge[L[now]=minf+1];
			if (now!=1) now=rev[now]->p;
		}
	}
}
int main(){
	int x,y,z;
	freopen("ditch.in","r",stdin);
	freopen("ditch.out","w",stdout);
	while(scanf("%d%d",&m,&n)!=EOF){
		data=T;
		sum=0; memset(head,0,sizeof(head));
		memset(now_head,0,sizeof(now_head));
		for(int i=1;i<=m;i++){
			scanf("%d%d%d",&x,&y,&z);
			if (x==y) continue;
			head[x]=new ((void*) data++) list(y,z,head[x]);
			head[y]=new ((void*) data++) list(x,0,head[y]);
			head[x]->b=head[y]; head[y]->b=head[x];
		}ISAP();
		printf("%d\n",sum);
	}
	return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值