网络流初步

最大流&最小费用最大流
//网络流的 基 本 模板还 非 常 不熟悉!


犯过的错误:

  1. Dinic最大流没写 if(x==T)return in;
  2. Dinic最大流没写 if(we[z]&&dis[y]==dis[x]+1)
  3. 建图时的边权数组 we 开得不够大

最大流(dinic算法)

求最大流的方法有FF,EK,dinic,dinic最优

dinic算法的核心是对图分层

定义一个节点的“层”\(dis_x\)\(x\)到源点\(s\)的距离。可以通过一遍bfs对图分好层

dinic算法规定:每次流水只能从第i层流向第i+1层,不能在同一层流,也不能回流。同时为了反悔,增加了反向边,通常把一组反向边的编号\(i,j\)设为2,3;4,5;6,7,从而可以由e异或1方便地得到它的反向边编号。每当流过一条边时,就把本边限流量-真实流量,反向边流量+真实流量

显然,只有流量为正的边才能流

当有一时刻发现源点汇点不再联通,就无法给图分层,于是算法结束

复杂度\(O(n^2m)\)

#include <bits/stdc++.h>
using namespace std;
const int N=105;
int n,m,s,t,tot=1,dis[N],cur[N];
long long we[10005];
vector<pair<int,int> >G[N];
queue<int>Q;//不要这样用stl::queue,用手写queue
bool bfs(){
memset(cur,0,sizeof cur);
	memset(dis,0,sizeof(dis));
	Q.push(s);dis[s]=1;
	while(!Q.empty()){
		int x=Q.front();Q.pop();
		for(int i=0;i<G[x].size();i++){
			int y=G[x][i].first,z=G[x][i].second;
			if(we[z]&&!dis[y])dis[y]=dis[x]+1,Q.push(y);
		}
	}
	return dis[t];
}
long long dfs(int x,long long in){
	if(x==t)return in;
	long long out=0;
	for(int i=cur[x];i<G[x].size();i++){//当前弧优化
cur[x]=i;
        if(!in)return out;
		int y=G[x][i].first,z=G[x][i].second;
		if(we[z]&&dis[y]==dis[x]+1){
			long long los=dfs(y,min(in,we[z]));
			we[z]-=los,we[z^1]+=los;
			in-=los,out+=los;
		}
	}
	if(!out)dis[x]=-1;
	return out;
}
void ade(int u,int v,int w){
	G[u].push_back(make_pair(v,++tot)),we[tot]=w;
	G[v].push_back(make_pair(u,++tot)),we[tot]=0;
}
int main(){
	cin>>n>>m>>s>>t;
	for(int i=1,u,v,w;i<=m;i++)cin>>u>>v>>w,ade(u,v,w);
	long long ans=0;
	while(bfs())ans+=dfs(s,1e18);
	cout<<ans;
}

最小费用最大流(EK算法)

贪心,每次寻找s->t的费用最短路,路径上的所有边的流量最小值即为这一次的流量Min,那么这次所消耗的费用Min*(边的费用之和)

同样地,每次-Min后反向边+Min

进行若干次,直到图不连通(无法找到最短路)

最短路可以用dij/spfa

复杂度\(O(nm^2)\)(通常情况下不会达到)

#include <bits/stdc++.h>
using namespace std;
const int N=5e3+5,M=1e5+5,INF=0x3f3f3f3f;
int n,m,s,t,p=1,dis[N],we[M],inq[N];
struct edge {
	int u,c,id;
}pre[N];
vector<edge>G[N];
queue<int>Q;
bool spfa(){
	memset(dis,0x3f,sizeof(dis));
	dis[s]=0;Q.push(s);inq[s]=1;
	while(!Q.empty()){
		int x=Q.front();Q.pop();inq[x]=0;
		for(int i=0;i<G[x].size();i++){
			int y=G[x][i].u,c=G[x][i].c,z=G[x][i].id;
			if(we[z]&&dis[y]>dis[x]+c){
				dis[y]=dis[x]+c;
				pre[y].u=x,pre[y].c=c,pre[y].id=z;
				if(!inq[y]){
					inq[y]=1;
					Q.push(y);
				}
			}
		}
	}
	return dis[t]!=INF;
}
int main(){
	cin>>n>>m>>s>>t;
	for(int i=1,u,v,w,c;i<=m;i++){
		cin>>u>>v>>w>>c;
		G[u].push_back((edge){v,c,++p});
		G[v].push_back((edge){u,-c,++p});
		we[p^1]=w,we[p]=0;
	}
	int ans=0,flow=0;
	while(spfa()){
		int Min=INF;
		for(int i=t;i!=s;i=pre[i].u)Min=min(Min,we[pre[i].id]);
		for(int i=t;i!=s;i=pre[i].u){
			we[pre[i].id]-=Min,we[pre[i].id^1]+=Min;
			ans+=Min*pre[i].c;
		}
		flow+=Min;
	}
	cout<<flow<<' '<<ans;
}
posted @ 2021-09-15 21:57  pengyule  阅读(31)  评论(0编辑  收藏  举报