网络流 Dinic 算法笔记
步骤
- 建图,初始时令反向边权值为零,之后将该边每次用去的权值累计赋值给该反向边。
- 分层,每次只能找下一个层的点。
- 每次多向找增广路,并将跑满的边去掉,之后再去跑残量网络,直到榨干所有可用管道。
大致就这样,然后注意时时减脂优化。
code
#include<bits/stdc++.h>
using namespace std;
#define int long long
const int N=200+5;
int iter[N];
int n,m,s,t;
const int MAXN=(1<<30);
struct edge{int to,v,re;
};
vector<edge>g[N];
#define FOR(i,_l,_r) for(int i=_l;i<=_r;i++)
void build(int u,int v,int w){g[u].push_back(edge{v,w,(int)g[v].size()});g[v].push_back(edge{u,0,(int)g[u].size()-1});
}
int depth[N];
void bfs(){memset(depth,-1,sizeof depth);queue<int>q;depth[s]=0;q.push(s);while(q.size()){int u=q.front();q.pop(); for(auto &e:g[u]){if(e.v>0&&depth[e.to]<0){depth[e.to]=depth[u]+1;q.push(e.to);}}}
}
int dfs(int u,int f){if(u==t||!f) return f;int ans=0;for(int &i=iter[u];i<(int)g[u].size();i++){//当前弧优化edge &e=g[u][i];if(e.v>0&&depth[e.to]==depth[u]+1){int d=dfs(e.to,min(f,e.v));if(d){e.v-=d;g[e.to][e.re].v+=d; f-=d;ans+=d;if(!f) break;}}}return ans;
}
int dinic(){int ans=0;while(1){bfs();if(depth[t]<0) return ans;memset(iter,0,sizeof iter);ans+=dfs(s,MAXN);}
}
signed main(){cin>>n>>m>>s>>t;FOR(i,1,m){int u,v,w;cin>>u>>v>>w;build(u,v,w);}cout<<dinic()<<endl;return 0;
}
调试心得小结
- 注意存图时的反向边是建在哪个节点上的。
!f
只能用来判断 \(f\) 是否为 \(0\) ,其于f<0
并非等价,比如当 \(f\) 的值为 \(-1\) 时会出现无法预料的错误(调了好久)。- 是
#define int long long
,不要吧int
和long long
错位,是用前一个关键字来代替后一个关键字,与typedef
刚好相反。
完结撒花。
yingxilin
Qian·JX の joker
2024-12-28 于玉山一中