最大流问题

dinic算法

 

blog

#include <iostream>
#include <cstdio>
#include <queue>
#include <cstring>
using namespace std;

/* 维护一个残余网络,c[i]表示正向残余流, c[i^1]表示反向残余流*/

const int N = 210, M = N*N;
const int INF = 0x3f3f3f3f;
int h[N], ne[M], e[M], idx, c[M];       //c存储边的容量
int dis[N];               //记录层次图中每个点的层数
int n, m; 
int S;      //源点
int T;      //汇点

void add(int a, int b, int w)
{
	e[idx]=b; ne[idx]=h[a]; 
	c[idx]=w; h[a]=idx++;
}

bool bfs()
{                                       //bfs在残量图上重新分层,如果汇点在层次图中,则返回true
	queue<int> q;
	for(int i=1;i <= n;i++) dis[i]=0;   //置为0,表示还未分配层数
	q.push(S); dis[S]=1;                //源点赋层数为1
	while(!q.empty()){       
		int u=q.front();
		q.pop();
		if(u==T) return true;             
		for(int i=h[u]; ~i; i=ne[i])
		{
			int j=e[i];
			if(!dis[j] && c[i]>0 )     //可以分配
			{                          //未分配层数并且可分配(余量大于0)
			    dis[j]=dis[u]+1;
			    q.push(j);
			}
		}
	}
	return false;
}

int dfs(int u, int flow)
{                                   //dfs求当前节点到汇点的最大流(dinic可以一次求出,主要利用dfs的回溯)
	if(u==T) return flow;
	int res=0; 
	int _flow=0;                    //从u出发的点的最大流
	for(int i=h[u]; ~i; i=ne[i])
	{
		int j=e[i];
		if(c[i]>0 && dis[u]+1==dis[j])  //下一层次点
		{
	     	_flow=dfs(j, min(flow-res, c[i]));  //不会超过前面点的最大流也不会超过边的余流量
			res+=_flow;                                 
			c[i]-=_flow;               //正向减去增广
			c[i^1]+=_flow;             //反向加上增广
    	}
    }
	return res;
}

int dinic()
{                           //直到残量图不连通
	int ans=0;
	while(bfs()) 
	{
	    ans+=dfs(S, INF);
	}
	return ans;
}

int main()
{
	cin>>m>>n;
    memset(h, -1, sizeof h);
	S=1; T=n;
	for(int i=0;i<m;i++){
		int a, b, w;
		scanf("%d%d%d",&a,&b,&w);
		add(a,b,w);
	    add(b,a,0);
	}
	printf("%d\n",dinic());
   
	return 0;
}
posted @ 2022-04-15 17:42  兮何其  阅读(30)  评论(0)    收藏  举报