Dinic 算法

#include<bits/stdc++.h>
#define int long long
using namespace std;
const int N = 10010; 
const int M = 200010; //由于残留网络有反向边,乘二
const int INF = 1e12;//无穷大,给个大点的数即可
int n,m,S,T;//n为点数,m为边数,S为源点,T为汇点 

/*存储用邻接表来存*/
int h[N];//表头
int e[M];//邻点
int f[M];//注意!!这里是容量
//代码中f表示为当前残留网络的容量 
int ne[M],idx;

int q[N];//队列
int d[N];//层数,因为要建立分层图防止环路存在dfs死循环

int cur[N];//当前弧优化

void add(int a,int b,int c)
//考虑建立反向边,注意反向边容量为0 
{
	e[idx]=b,f[idx]=c,ne[idx]=h[a],h[a]=idx++;
	e[idx]=a,f[idx]=0,ne[idx]=h[b],h[b]=idx++;
}

bool bfs(){
	int hh=0,tt=0;
	memset(d,-1,sizeof(d));
	q[0]=S;//起点为源点
	d[S]=0;//层数归零 
	cur[S]=h[S];//弧初始化 
	while(hh<=tt){
		int t=q[hh++];//取出对头元素
		for(int i=h[t];~i;i=ne[i]){
			int ver=e[i];
			if(d[ver]==-1&&f[i])//如果当前点没有被搜过且容量大于零 
			{
				d[ver]=d[t]+1;//层数+1
				cur[ver]=h[ver];
				if(ver==T)//如果已经找到了终点(汇点) 
					return true;
				q[++tt]=ver;
			}
		} 
	} 
	return false;
}

int find(int u,int limit)
//从u开始搜
//从源点流向u的最大流量 
{
	if(u==T) return limit;
	int flow=0;//表示u往后流的最多流量 
	for(int i=cur[u];~i&&flow<limit;i=ne[i]){
		cur[u]=i;//当前弧优化 
		int ver=e[i];
		if(d[ver]==d[u]+1&&f[i]){
			int t=find(ver,min(f[i],limit-flow));
			if(!t) d[ver]=-1;//删掉这条边
			f[i]-=t;
			f[i^1]+=t;//反向弧加上t
			flow+=t; 
		}
	} 
	return flow;
}

int dinic(){
	int r=0;//累加流量
	int flow;
	while(bfs()){
		while(flow=find(S,INF)){
			r+=flow;
		}
	} 
	return r;
}

signed main(){
	cin>>n>>m>>S>>T;
	memset(h,-1,sizeof h);
	while(m--){
		int a,b,c;
		cin>>a>>b>>c;
		add(a,b,c);
	}
	cout<<dinic()<<endl;
	return 0;
} 

 
 
 
posted @ 2022-07-08 23:17  PassName  阅读(51)  评论(0编辑  收藏  举报