网络流 Dinic 算法笔记

网络流 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 ,不要吧 intlong long 错位,是用前一个关键字来代替后一个关键字,与 typedef 刚好相反。

完结撒花。

yingxilin
Qian·JX の joker
2024-12-28 于玉山一中

posted @ 2024-12-28 12:45  Qian·JXのjoker  阅读(18)  评论(0)    收藏  举报