191107-网络流

191107-网络流练习

一,最大流问题

1),Edmonds-Karp算法

时间复杂度为 O ( n m 2 ) O(nm^2) O(nm2) 一般能处理 1 0 3 − 1 0 4 10^3-10^4 103104规模的网络

模板
#include<bits/stdc++.h>
#define M 200006
const int inf=1e8;
int maxn,n,m,s,t,nxt[M*2],first[M],to[M*2],w[M*2],incf[M],pre[M],tot=1;//tot要从1开始 
bool vis[M];
using namespace std;
void add(int x,int y,int z){
	nxt[++tot]=first[x],first[x]=tot,to[tot]=y,w[tot]=z;
	nxt[++tot]=first[y],first[y]=tot,to[tot]=x,w[tot]=0;
}
bool bfs(){
	memset(vis,0,sizeof(vis));
	queue<int>q;
	q.push(s);
	vis[s]=1;
	incf[s]=inf;
	while(!q.empty()){
		int v=q.front();
		q.pop();
		for(int i=first[v];i;i=nxt[i]){
			if(w[i]){
				int u=to[i];
				if(vis[u]) continue;
				incf[u]=min(incf[v],w[i]);
				pre[u]=i;
				q.push(u);
				vis[u]=1;
				if(u==t) return true;
			}
		}
	}
	return false;
}
void update(){
	int v=t;
	while(v!=s){
		int u=pre[v];
		w[u]-=incf[t];
		w[u^1]+=incf[t];
		v=to[u^1];
	}
	maxn+=incf[t];
}
int main(){
	int x,y,z;
	scanf("%d%d%d%d",&n,&m,&s,&t);
	for(int i=1;i<=m;i++){
		scanf("%d%d%d",&x,&y,&z);
		add(x,y,z);
	}
	while(bfs()) 
		update();
	printf("%d",maxn);
	return 0;
}

2),Dinic算法

时间复杂度为 O ( n 2 m ) O(n^2m) O(n2m),一般能处理 1 0 4 − 1 0 5 10^4-10^5 104105规模的网络

模板
#include<bits/stdc++.h>
#define M 200006 
using namespace std;
const int inf=1e8;
int to[M*2],nxt[M*2],w[M*2],first[M],tot=1,d[M],now[M],n,m,s,t,ans;
void add(int x,int y,int z){
	nxt[++tot]=first[x],first[x]=tot,to[tot]=y,w[tot]=z;
	nxt[++tot]=first[y],first[y]=tot,to[tot]=x,w[tot]=0;
}
bool bfs(){
	memset(d,0,sizeof(d));
	queue<int>q;
	q.push(s);
	d[s]=1;
	now[s]=first[s];
	while(q.size()){
		int v=q.front();
		q.pop();
		for(int i=first[v];i;i=nxt[i]){
			int u=to[i];
			if(w[i]&&!d[u]){
				q.push(u);
				now[u]=first[u];
				d[u]=d[v]+1;
				if(u==t) return 1;
			}
		}
	} 
	return 0;
}
int dinic(int x,int flow){
	if(x==t) return flow;
	int rest=flow,k,i;
	for(i=now[x];i&&rest;i=nxt[i]){
		int u=to[i];
		if(w[i]&&d[u]==d[x]+1){
			k=dinic(u,min(rest,w[i]));
			if(!k) d[u]=0;
			w[i]-=k;
			w[i^1]+=k;
			rest-=k;
		}
	}
	now[x]=i;
	return flow-rest;
} 
int main(){
	int flow=0,x,y,z;
	scanf("%d%d%d%d",&n,&m,&s,&t);
	for(int i=1;i<=m;i++){
		scanf("%d%d%d",&x,&y,&z);
		add(x,y,z);
	}
	while(bfs())
		while(flow=dinic(s,inf)) ans+=flow;
	printf("%d",ans);
	return 0;
} 

3),解决二分图最大匹配问题

解析

建立一个源点和汇点,从源点S到做左部点连一条有向边,从每个右部点向汇点T连一条有向边,网络中每条边的容量都为1,最大流即为最大匹配数

题解

二,最小割问题

三,费用流

最小费用最大流

模板 (dinic)
#include<bits/stdc++.h>
#define M 200006
using namespace std;
const int inf=1e8;
int f[M*2],w[M*2],to[M*2],first[M],nxt[M*2],tot=1,d[M],n,m,s,t,ans,ret,now[M],ans1;
bool vis[M];
void add(int x,int y,int z,int v){
	nxt[++tot]=first[x];
	first[x]=tot;
	to[tot]=y;
	w[tot]=z;
	f[tot]=v;
}
bool spfa(){
	for(int i=1;i<=n;i++) d[i]=inf;
	memset(vis,0,sizeof(vis));
	memcpy(now,first,sizeof(first));
	queue<int>q;
	q.push(s);
	vis[s]=1;
	d[s]=0;
	while(q.size()){
		int v=q.front();
		q.pop();
		vis[v]=0;
		for(int i=first[v];i;i=nxt[i]){
			int u=to[i];
			if(w[i]&&d[u]>d[v]+f[i]){
				d[u]=d[v]+f[i];
				if(!vis[u]){
					q.push(u);
					vis[u]=1;
				}
			}
		}
	}
	return d[t]!=inf;
}
int dfs(int r,int flow){
	if(t==r) return flow;
	vis[r]=1;
	int ans=0,i;
	for(i=now[r];i&&ans<flow;i=nxt[i]){
		int u=to[i];
		if(!vis[u]&&w[i]&&d[u]==d[r]+f[i]){
			int x=dfs(u,min(w[i],flow-ans));
			if(x){
				ret+=f[i]*x;
				w[i]-=x;
				w[i^1]+=x;
				ans+=x;
			}
		}
	}
	now[r]=i;//可以开当前弧优化 
	vis[r]=0;
	return ans;
}
int main(){
	int x,y,z,v;
	scanf("%d%d%d%d",&n,&m,&s,&t);
	for(int i=1;i<=m;i++){
		scanf("%d%d%d%d",&x,&y,&z,&v);
		add(x,y,z,v);
		add(y,x,0,-v);
	}
	int flow=0;
	while(spfa()){
		memset(vis,0,sizeof(vis));//清不清0都能过? 
		while(flow=dfs(s,inf)) ans1+=flow;
	}
	printf("%d %d",ans1,ret);
	return 0;
}

练习题

网络流24题

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值