求解最大流主要有两种算法:增广路算法和预流推进算法
增广路算法的本质是考虑“压榨”完残量网络中所有仍然有流量的边并记录答案。
所以最基本的想法是递归搜索出所有与节点 \(u\) 相连的边求解答案。
这样的复杂度太高,可以发现这样的问题主要在于深搜必须统计出所有路径才能计算答案,考虑将深搜改为广搜,这样的好处在于找到的增广路一定是最短的,大大节省了时间复杂度。
找增广路的具体操作是在加边的同时建反向边,表示流过去的流量或者说是可以“反悔”的流量,这样就成功找出了最优的增广路。
但是广搜经常会搜出来一些无意义的边,比如从深度更高的点向搜到了深度更低的点,这样的边无法对答案造成影响,所以先搜出所有点的深度,每次 dinic 操作前判断两点深度。
#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cstdlib>
#include<cmath>
#include<deque>
#include<queue>
#include<map>
#include<vector>
#define int long long//
using namespace std;
const int INF = 2e15;
const int mod = 1e9 + 7;
const int N = 5e3 + 10;
inline int read(){
int x=0,f=1;char ch=getchar();
for(;!isdigit(ch);ch=getchar()) if(ch=='-') f=-1;
for(; isdigit(ch);ch=getchar()) x=(x<<3)+(x<<1)+ch-'0';
return x*f;
}
struct Edge{
int u,v,next,w;
}edge[N<<1];
int head[N],idx = 1;
void add(int a,int b,int c){
edge[++idx].u = a , edge[idx].v = b , edge[idx].w = c;
edge[idx].next = head[a] , head[a] = idx;
}
int n,m,s,l;
int dis[N],cur[N];
queue<int> q;
inline int bfs(){
memset(dis,0,sizeof(dis));
while(!q.empty()) q.pop();
q.push(s) , dis[s] = 1 , cur[s] = head[s];
while(!q.empty()){
int u = q.front();q.pop();
for(int i=head[u];i;i=edge[i].next){
int v = edge[i].v;
if(edge[i].w && !dis[v]){
q.push(v);
cur[v] = head[v];
dis[v] = dis[u] + 1;
if(v == l) return true;
}
}
}
return false;
}
inline int dinic(int u,int flow){
if(u == l) return flow;
int res = flow , k;
for(int i=head[u];i;i=edge[i].next){
int v = edge[i].v;
if(edge[i].w && dis[v] == dis[u] + 1){
k = dinic(v,min(res,edge[i].w));
if(!k) dis[v] = 0;
edge[i].w -= k , edge[i^1].w += k;
res -= k;
}
cur[u] = i;
}
return flow - res;
}
int max_flow;
signed main(){
n = read() , m = read() , s = read() , l = read();
for(int i=1;i<=m;i++){
int u = read() , v = read() , w = read();
add(u,v,w); add(v,u,0);
}
int flow = 0;
while(bfs()){
while(flow = dinic(s,INF)) max_flow += flow;
}
cout<<max_flow<<"\n";
return 0;
}
/*
*/
标签:ch,最大,int,read,edge,dinic,include,dis
From: https://www.cnblogs.com/0x3F/p/17091582.html