1. 程式人生 > 其它 >362 網路流 最大流 Dinic 演算法

362 網路流 最大流 Dinic 演算法

視訊連結:

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

const int N=10010,M=200010,INF=1e8;
int n,m,S,T;
int h[N],e[M],f[M],ne[M],idx;
int d[N];//點在分層圖中的編號(即到源點最短路徑)
int cur[N];//當前弧優化,儲存從當前節點開始還需要遍歷的邊的編號

void add(int a,int b,int c){
  e[
++idx]=b,f[idx]=c,ne[idx]=h[a],h[a]=idx; } bool bfs(){ queue<int> q; memset(d,-1,sizeof d); q.push(S),d[S]=0,cur[S]=h[S]; while(q.size()){ int u=q.front();q.pop(); for(int i=h[u];i;i=ne[i]){ int v=e[i]; if(d[v]==-1&&f[i]){ d[v]=d[u]+1;//點所在層 cur[v]=h[v];//
當前弧是第一條邊 if(v==T) return true; q.push(v); } } } return false; } int find(int u,int limit){//多路增廣,累加路流 // 從起點S到當前點u允許流過的最大流量為limit if(u==T) return limit; int flow=0;//從u開始向後面流的最大的流量 // i=cur[u] 跳過前面從u出去的已經流滿的路徑 // flow < limit 說明還有必要搜從u出去的剩餘的邊 for(int
i=cur[u];i&&flow<limit;i=ne[i]){ // 如果進入迴圈,說明搜到從u出去編號為i的邊 // 進而說明前面從u指出去的弧已經被搜完了,這些弧的流量已經被"榨乾"了 // 因此dinic下一次呼叫find時,直接從i開始搜即可 cur[u]=i; //當前弧優化 int v=e[i]; if(d[v]==d[u]+1&&f[i]){ // S~u的流量為limit,u~各分支~T的流量和為flow int t=find(v,min(f[i],limit-flow)); // t==0 說明不能找到從v到T的增廣路 // 因此下一次遍歷到v時直接跳過即可 if(!t) d[v]=-1;//枯竭點優化 // 更新殘留網路 f[i]-=t;f[i^1]+=t;flow+=t; } } return flow; } int dinic(){ int res=0,flow; while(bfs()) while(flow=find(S,INF)) res+=flow; return res; } int main(){ int a,b,c; scanf("%d%d%d%d",&n,&m,&S,&T); idx=1; while(m -- ){ scanf("%d%d%d",&a,&b,&c); add(a,b,c); add(b,a,0); } printf("%d\n",dinic()); return 0; }