浅谈网络流最大流
P3376 【模板】网络最大流
首先我们都已经知道了网络的定义和各种各样的东西。
最大流就是从源点到汇点的最多能流的流量,可以类比二分图的最大匹配。考虑怎么来求她。
Dinic算法
建图没话说,一条正弧一条反弧。
void adde(int u,int v,int cap){
edges.pb({u,v,cap,0});
G[u].pb(edges.size()-1);
edges.pb({v,u,0,0});
G[v].pb(edges.size()-1);
}
首先我们可以用找增广路的思路,每次去找在当前基础上有没有更优的(更多流量的)方案。我们称每次找到的这个最大的量为 可改进量 。
我们可以用 \(dfs\) 的思想去找这个可改进量,但是由于 \(dfs\) 是走路不看路的,你得给她建一个盲道,这就是层次图了。由于 \(bfs\) 是按层次来搜的,所以我们可以先搜一遍,求出每个点所对应的层次,这样 \(dfs\) 就不会乱走了。
bool BFS(){
memset(dis,-1,sizeof(dis));
queue<int> q;
q.push(src);
dis[src]=0;
while(!q.empty()){
int u=q.front();q.pop();
for(int i=0;i<G[u].size();i++){
Edge e=edges[G[u][i]];
if(dis[e.to]==-1&&e.cap>e.flow){
dis[e.to]=dis[u]+1;
q.push(e.to);
}
}
}
return dis[dst]!=-1;
}
这个还可以顺带判断网络还能不能再改进了。
有个这个后,我们就可以愉快的用 \(dfs\) 求可改进量了!
int dfs(int u,int a){//u为当前点,a为当前最大可用的流量,返回值为可改进量
if(u==dst||!a) return a;//如果走到汇点dst或当前没有可用的流量了,就返回
int flow=0;
for(int &i=cur[u];i<G[u].size();i++){//当前弧优化(后面会讲到)
Edge &e=edges[G[u][i]];
if(dis[u]+1==dis[e.to]){//按层次图来走
int f=dfs(e.to,min(a,e.cap-e.flow));//a每次都要取min
e.flow+=f;
edges[G[u][i]^1].flow-=f;//一条弧流量增加f,另一条弧就要减f,用于反悔
flow+=f;
a-=f;
if(!a) break;//没可用流量就break掉
}
}
return flow;//当前点u的可改进量
}
如果没有当前弧优化的话,我们可能会重复走一些点。但是对于一个点来说,如果求出了她的可改进量,那么就相当于把这个点可用的潜能全榨干了,下一次再重算就没有意义了,所以我们对于每一点,我们都保证再这一次的 \(dfs\) 中,她的出边只会走一次,这样就可以省下一些冗余操作。
求最大流部分
int maxflow(int s,int t){
src=s,dst=t;//源点和汇点
int flow=0;
while(BFS()){
memset(cur,0,sizeof(cur));//当前弧优化标记清零
flow+=dfs(s,INF);//从s点出发有INF的流量可以用
}
return flow;
}
\(code\)
#include<bits/stdc++.h>
#define int long long
#define pb push_back
using namespace std;
inline int read(){
int ans=0,f=1;char ch=getchar();
while(!isdigit(ch)){if(ch=='-') f=-f;ch=getchar();}
while(isdigit(ch)){ans=(ans<<3)+(ans<<1)+ch-48;ch=getchar();}
return ans*f;
}
const int N=5005,M=205,INF=1e9;
int n,m,s,t;
int src,dst;
int cur[M];
int dis[M];
struct Edge{
int from,to,cap,flow;
};
vector<Edge> edges;
vector<int> G[M];
void adde(int u,int v,int cap){
edges.pb({u,v,cap,0});
G[u].pb(edges.size()-1);
edges.pb({v,u,0,0});
G[v].pb(edges.size()-1);
}
bool BFS(){
memset(dis,-1,sizeof(dis));
queue<int> q;
q.push(src);
dis[src]=0;
while(!q.empty()){
int u=q.front();q.pop();
for(int i=0;i<G[u].size();i++){
Edge e=edges[G[u][i]];
if(dis[e.to]==-1&&e.cap>e.flow){
dis[e.to]=dis[u]+1;
q.push(e.to);
}
}
}
return dis[dst]!=-1;
}
int dfs(int u,int a){
if(u==dst||!a) return a;
int flow=0;
for(int &i=cur[u];i<G[u].size();i++){
Edge &e=edges[G[u][i]];
if(dis[u]+1==dis[e.to]){
int f=dfs(e.to,min(a,e.cap-e.flow));
e.flow+=f;
edges[G[u][i]^1].flow-=f;
flow+=f;
a-=f;
if(!a) break;
}
}
return flow;
}
int maxflow(int s,int t){
src=s,dst=t;
int flow=0;
while(BFS()){
memset(cur,0,sizeof(cur));
flow+=dfs(s,INF);
}
return flow;
}
signed main(){
n=read(),m=read(),s=read(),t=read();
for(int i=1;i<=m;i++){
int x=read(),y=read(),v=read();
adde(x,y,v);
}
printf("%lld",maxflow(s,t));
return 0;
}