【整合】网络流ISAP算法模板

注释应该比较清楚了吧= =
#include<iostream>
#include<cstdio>
#include<cstring>
#include<cmath>
#include<algorithm>
#define MAXN 2048
#define MAXINT 0x7fffffff
using namespace std;
int n,m;//点的数目和边的数目
int dis[MAXN+1];//距离标号 
int num[MAXN+1];
int src,des;//src源点,des汇点 
int u,v,w;
struct edge
{
	int f; 
	int c;
	int ver;
	edge *rev;
	edge *next;
	edge(){};
	edge(int v,int cap,edge *nex):ver(v),c(cap),next(nex),rev(NULL),f(0){};
	void* operator new(size_t, void *p)
	{
 		return p;
 	}
}*s[MAXN+1];
void init()
{
	int queue[MAXN+1],head=0,tail=0;
	for (int i=1;i<=n;i++)
	    dis[i]=MAXN,num[i]=0;
	queue[tail++]=des;
	dis[des]=0;
	num[0]=1;
	while (head!=tail)
	{
		int v=queue[head++];
		edge *e=s[v];
		while (e)
		{
			if ((e->rev)&&(e->rev->c==0)||dis[e->ver]<MAXN) {}//若改点后的边不可通过
			//流或者已经更新就无需更新
			else 
			{
				dis[e->ver]=dis[v]+1;
				++num[dis[e->ver]];
				queue[tail++]=e->ver;
			}
			e=e->next;
		}
	}
}
int maxflow()//ISAP算法实现过程 
{
	int st=src,ret=0;
	edge *E[MAXN],*rep[MAXN];
	for (int i=1;i<=n;i++) E[i]=s[i];
	while (dis[src]<n)//不存在增广路径就停止 
	{
		if (st==des)//找到了增广路径 
		{
			int delta=MAXINT;
			for (int i=src;i!=des;i=E[i]->ver)
				delta=min(delta,E[i]->c);
			for (int i=src;i!=des;i=E[i]->ver)
			{
				E[i]->c-=delta;
				E[i]->f+=delta;
				E[i]->rev->c+=delta;
				E[i]->rev->f-=delta;
			}
			ret+=delta;
			st=src;
		}
		edge *e;
		for (e=E[st];e;e=e->next)
			if (e->c>0&&dis[st]==dis[e->ver]+1) break;
		if (e)//存在允许弧 
		{
			E[st]=e;
			rep[e->ver]=e->rev;
			st=e->ver;
		}
		else
		{
			if ((--num[dis[st]])==0) break;//GAP优化 
			E[st]=s[st];
			int mind=n;
			for (edge *t=s[st];t;t=t->next)
				if (t->c>0)
				    mind=min(mind,dis[t->ver]);
			dis[st]=mind+1;
			++num[dis[st]];
			if (st!=src) st=rep[st]->ver;
		}
    }
	return ret;
}
int main()
{
	freopen("ditch.in","r",stdin);
	freopen("ditch.out","w",stdout);
	scanf("%d%d",&m,&n);
	src=1,des=n;
	edge *buffer=new edge[2*m];
 	edge *data=buffer;
	while (m--)
	{
		scanf("%d%d%d",&u,&v,&w);
		s[u]=new((void*) data++) edge(v,w,s[u]);
		s[v]=new((void*) data++) edge(u,0,s[v]);
		s[u]->rev=s[v];
		s[v]->rev=s[u];
	}
	init();
	printf("%d",maxflow());
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值