1. 程式人生 > 實用技巧 >最大網路流dinic

最大網路流dinic

  1. 初始化flow(最大流量)為INF(極大值),建邊(正向弧和反向弧)
  2. bfs尋找增廣路看看有沒有路,順便進行深度標號。如果沒有路直接結束輸出flow。
  3. 如果有,我們按照深度dfs。dfs時注意在給正向弧減權時給反向弧加權。
  4. ans+=flow,重複2到4步驟,直到無路可走。
  5. 輸出結束~

以上就是網路流全部內容(誤

概念什麼的就不講啦~

下面來仔細分析板子程式碼。

  • 初始化ans=0,構建邊
  • dinic中心:
while(BFS()) ans+=DFS(start,INF);
  • BFS:
inline bool BFS()
{
    memset(dep,-1,sizeof dep);
        
//每次BFS更新深度,-1代表未被更新或者無路徑訪問 dep[s]=0; //起點的深度為0 q.push(s); while(!q.empty()) { int u=q.front();q.pop(); for(R int i=head[u];i;i=e[i].nxt) if(e[i].dis and dep[e[i].to]==-1)//一定有流並且未被訪問 dep[e[i].to]=dep[u]+1,q.push(e[i].to); } if(dep[end]==-1
)return 0;//如果end的深度為-1,無路徑到達,此時最大流 return 1; }
  • DFS
ll DFS(int x,ll flow)
{
    if(x==end) return flow;//到終點就返回流
    ll used=0;//優化,記錄已用過的流
    for(R int i=head[x];i;i=e[i].nxt)
    {
        int u=e[i].to;
        if(e[i].dis and dep[u]==dep[x]+1)
        {
            long long w=DFS(u,min(e[i].dis,flow-used));//
求出最大流 used+=w; e[i].dis-=w;e[i^1].dis+=w;//i^1為相反方向的邊,對應加權 if(used==flow)return flow; } } if(!used)dep[x]=-1;//無流可走,說明此點已經無意義了 return used;//最大流 }

P3376 【模板】網路最大流

#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<queue> 
#define R register
#define INF 1<<30
using namespace std;
template <typename T>
inline T read()
{
    T x=0;int w=0;char c=getchar();
    while(!isdigit(c))w|=c=='-',c=getchar();
    while(isdigit(c))x=(x<<3)+(x<<1)+(c^48),c=getchar();
    return w?-x:x;
}
namespace ysr
{
    typedef long long ll;
    const int maxn=100000;
    struct Edge{
        int to,nxt;
        ll dis;
    }e[200000];
    int cur[maxn],head[maxn],ecnt=1;//這裡記為-1的原因時便於訪問正向弧和反向弧 
    int n,m,s,end,dep[maxn];
    inline void addedge(int from,int to,ll dis){
        e[++ecnt].to=to,e[ecnt].nxt=head[from],e[ecnt].dis=dis,head[from]=ecnt;
    }
    inline void add(int from,int to,ll dis){
        addedge(from,to,dis);addedge(to,from,0);
    }
    ll DFS(int x,ll flow)
    {
        if(x==end) return flow;
        ll used=0;
        for(R int i=head[x];i;i=e[i].nxt)
        {
            int u=e[i].to;
            if(e[i].dis and dep[u]==dep[x]+1)
            {
                long long w=DFS(u,min(e[i].dis,flow-used));
                used+=w;
                e[i].dis-=w;e[i^1].dis+=w;
                if(used==flow)return flow;
            }
        }
        if(!used)dep[x]=-1;
        return used;
    }
    queue<int>q;
    inline bool BFS()
    {
        memset(dep,-1,sizeof dep);
        dep[s]=0;
        q.push(s);
        while(!q.empty())
        {
            int u=q.front();q.pop();
            for(R int i=head[u];i;i=e[i].nxt)
                if(e[i].dis and dep[e[i].to]==-1)
                    dep[e[i].to]=dep[u]+1,q.push(e[i].to);
        }
        if(dep[end]==-1)return 0;
        return 1;
    }
    inline void work()
    {
        n=read<int>(),m=read<int>(),s=read<int>(),end=read<int>();
        ll ans=0;
        int a,b;
        ll c;
        for(R int i=0;i<m;i++)a=read<int>(),b=read<int>(),c=read<ll>(),add(a,b,c);
        while(BFS())
            ans+=DFS(s,INF);
        printf("%lld\n",ans);
    }
}
signed main()
{
    ysr::work();
    return 0;
}

大家一定已經發現我定義了一個cur陣列不知道但什麼的。這其實就是【當前弧優化】的陣列,雖然我在上面沒有使用。

這也不是什麼高深的玩意。我們證明,如果一個點在之前的dfs中已經把一些邊考慮過了,由於在當前和以後的流的dfs中這些邊都是增廣過的,也就是再也沒法做出貢獻了,那麼我們用一個數組cur記錄一下考慮到哪裡瞭然後下一側dfs時接著上次的就行了。

#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<queue> 
#define R register
#define INF 1<<30
using namespace std;
template <typename T>
inline T read()
{
    T x=0;int w=0;char c=getchar();
    while(!isdigit(c))w|=c=='-',c=getchar();
    while(isdigit(c))x=(x<<3)+(x<<1)+(c^48),c=getchar();
    return w?-x:x;
}
namespace ysr
{
    typedef long long ll;
    const int maxn=100000;
    struct Edge{
        int to,nxt;
        ll dis;
    }e[200000];
    int cur[maxn],head[maxn],ecnt=1;//這裡記為-1的原因時便於訪問正向弧和反向弧 
    int n,m,s,end,dep[maxn];
    inline void addedge(int from,int to,ll dis){
        e[++ecnt].to=to,e[ecnt].nxt=head[from],e[ecnt].dis=dis,head[from]=ecnt;
    }
    inline void add(int from,int to,ll dis){
        addedge(from,to,dis);addedge(to,from,0);
    }
    ll DFS(int x,ll flow)
    {
        if(x==end) return flow;
        ll used=0;
        for(R int i=cur[x];i;i=e[i].nxt)
        {
            cur[x]=i;
            int u=e[i].to;
            if(e[i].dis and dep[u]==dep[x]+1)
            {
                long long w=DFS(u,min(e[i].dis,flow-used));
                used+=w;
                e[i].dis-=w;e[i^1].dis+=w;
                if(used==flow)return flow;
            }
        }
        if(!used)dep[x]=-1;
        return used;
    }
    queue<int>q;
    inline bool BFS()
    {
        for(R int i=0;i<=n;i++)cur[i]=head[i],dep[i]=-1;
        dep[s]=0;
        q.push(s);
        while(!q.empty())
        {
            int u=q.front();q.pop();
            for(R int i=head[u];i;i=e[i].nxt)
                if(e[i].dis and dep[e[i].to]==-1)
                    dep[e[i].to]=dep[u]+1,q.push(e[i].to);
        }
        if(dep[end]==-1)return 0;
        return 1;
    }
    inline void work()
    {
        n=read<int>(),m=read<int>(),s=read<int>(),end=read<int>();
        ll ans=0;
        int a,b;
        ll c;
        for(R int i=0;i<m;i++)a=read<int>(),b=read<int>(),c=read<ll>(),add(a,b,c);
        while(BFS())
            ans+=DFS(s,INF);
        printf("%lld\n",ans);
    }
}
signed main()
{
    ysr::work();
    return 0;
}
還是模板