网络流模版

九野的博客,转载请注明出处 : http://blog.csdn.net/acmmmm/article/details/11199941


Dinic非递归版:

#define N 5000
#define M 1505
#define inf 536870912

inline int Max(int a,int b){return a<b?b:a;}
inline int Min(int a,int b){return a>b?b:a;}

struct Edge{
	int from, to, cap, nex;
}edge[N*10];

int head[N*4], edgenum;
void addedge(int u, int v, int cap){
	Edge E = { u, v, cap, head[u]};
	edge[ edgenum ] = E;
	head[u] = edgenum ++;
}
int sign[N*4], s, t;
bool BFS(int from, int to){
	memset(sign, -1, sizeof(sign));
	sign[from] = 0;

	queue<int>q;
	q.push(from);
	while( !q.empty() ){
		int u = q.front(); q.pop();
		for(int i = head[u]; i!=-1; i = edge[i].nex)
		{
			int v = edge[i].to;
			if(sign[v]==-1 && edge[i].cap)
			{
				sign[v] = sign[u] + 1, q.push(v);
				if(sign[to] != -1)return true;
			}
		}
	}
	return false;
}
int Stack[N*4], top, cur[N*4];
int day;
int dinic(){

	int ans = 0;
	while( BFS(s, t) )
	{
		memcpy(cur, head, sizeof(head));
		int u = s;		top = 0;
		while(1)
		{
			if(u == t)
			{
				int flow = inf, loc;//loc 表示 Stack 中 cap 最小的边
				for(int i = 0; i < top; i++)
					if(flow > edge[ Stack[i] ].cap)
					{
						flow = edge[Stack[i]].cap;
						loc = i;
					}

					for(int i = 0; i < top; i++)
					{
						edge[ Stack[i] ].cap -= flow;
						edge[Stack[i]^1].cap += flow;
					}
					ans += flow;
					top = loc;
					u = edge[Stack[top]].from;
			}
			for(int i = cur[u]; i!=-1; cur[u] = i = edge[i].nex)//cur[u] 表示u所在能增广的边的下标
				if(edge[i].cap && (sign[u] + 1 == sign[ edge[i].to ]))break;
			if(cur[u] != -1)
			{
				Stack[top++] = cur[u];
				u = edge[ cur[u] ].to;
			}
			else
			{
				if( top == 0 )break;
				sign[u] = -1;
				u = edge[ Stack[--top] ].from;
			}
		}
	}
	return ans;
}


Dinic 递归版:


struct Edge{
	int from,to,flow,cap, nex;
}edge[M*2];//双向边,注意RE 注意这个模版是 相同起末点的边 合并而不是去重
int head[N],edgenum;//2个要初始化-1和0
void addedge(int u,int v,int cap){//网络流要加反向弧
	Edge E={u,v,0,cap,head[u]};
	edge[edgenum]=E;
	head[u]=edgenum++;
	Edge E2={v,u,0,cap,head[v]}; //这里的cap若是单向边要为0
	edge[edgenum]=E2;
	head[v]=edgenum++;
}


int dis[N],cur[N];//距离起点的距离 cur[i]表示i点正在考虑的边 优化不再考虑已经用过的点 初始化为head
bool vis[N];
bool BFS(int Start,int End){
	memset(vis,0,sizeof(vis)); 
	memset(dis,-1,sizeof(dis));
	queue<int>Q;	while(!Q.empty())Q.pop();
	Q.push(Start);	dis[Start]=0;	vis[Start]=1;
	while(!Q.empty())
	{
		int u = Q.front(); Q.pop();
		for(int i=head[u];i!=-1;i=edge[i].nex){
			Edge E =edge[i];
			if(!vis[E.to] && E.cap>E.flow)
			{
				vis[E.to]=1;
				dis[E.to]=dis[u]+1;
				if(E.to==End)return true;
				Q.push(E.to);
			}
		}
	}
	return false;
}
int DFS(int x, int a,int End){//流入x 的流量是a
	if(x==End || a==0)return a;
	int flow = 0, f;
	for(int& i=cur[x];i!=-1;i=edge[i].nex)
	{
		Edge& E = edge[i];
		if(dis[x]+1 == dis[E.to] && (f = DFS(E.to , Min(a, E.cap-E.flow), End))>0 )
		{
			E.flow += f;
			edge[ i^1 ].flow -= f;//反向边要减掉
			flow += f;
			a -= f;
			if(a==0)break;
		}
	}
	return flow;
}
int Maxflow(int Start,int End){
	int flow=0; 
	while(BFS(Start,End)){
		memcpy(cur,head,sizeof(head));//把head的数组复制过去
		flow += DFS(Start, inf, End);
	}
	return flow;
}



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值