Dinic 模板詳解

一、概述

Dinic演算法是最大流演算法中的一種,其時間複雜度為O(n^2*m),但是有更好的最壞時間複雜度O(nm*log(U)),與Hopcroft−Karp的O(m^2*n^0.5)相比,在密集圖或者容量較大時,Dinic演算法對於求解最大流有更好的表現,適用性更廣。

二、原理

Dinic演算法的基本思路是:通過多次增廣,每次增加的流量不低於上一次增加的流量,直至無法增廣為止,這樣求得的就是最大流量。

具體思路如下:

1.首先設置dfs流程,使其能夠和BFS流程相對應,dfs的返回值代表可以從當前節點流入匯點的最大流量,如果當前節點等於源點就返回無窮大(因為一開始源點的可行流量等於無窮)

2.其次,設置BFS流程,使其在調用dfs時可以從當前節點到達匯點(即dist[t]!=-1),並返回增加的流量,如果增加的流量為0或者小於0,則直接break(即優化掉死路)

3.最後通過不停的調用BFS和DFS,每次維護一組殘量圖,直到不存在增廣路為止。整個過程中,每次增廣的流量都會不小於上一次的增加量,因此需要滿足連續增廣,並且BFS成功與否決定了DFS會返回多大的可行流量。

三、應用

Dinic演算法的應用主要在網路流中,可以求一個圖中所有源點到匯點的最大流量(源點可能有多個),並且對於同一對源點-匯點,最多可以同時執行一次Dinic演算法。

代碼示例:

typedef int type; // 容量,類型名稱視情況更改

struct edge
{
    int to,rev;
    type cap;
};

vector G[MAXV];
int iter[MAXV],level[MAXV];

void add_edge(int from,int to,type cap)
{
    G[from].push_back((edge){to,(int)G[to].size(),cap});
    G[to].push_back((edge){from,(int)G[from].size()-1,0});
}

void bfs(int s)
{
    memset(level,-1,sizeof(level));
    queue q;
    level[s]=0;
    q.push(s);
    while(!q.empty())
    {
        int v=q.front();
        q.pop();
        for(int i=0;i0&&level[e.to]<0)
            {
                level[e.to]=level[v]+1;
                q.push(e.to);
            }
        }
    }
}

type dfs(int v,int t,type f)
{
    if(v==t)return f;
    for(int &i=iter[v];i0&&level[v]0)
            {
                e.cap-=d;
                G[e.to][e.rev].cap+=d;
                return d;
            }
        }
    }
    return 0;
}

type max_flow(int s,int t)
{
    type flow=0;
    for(;;)
    {
        bfs(s);
        if(level[t]0)
        {
            flow+=f;
        }
    }
}

四、優化

Dinic演算法的常見優化方法有:

1.分層圖(Level Graph):最寬鬆的限制即每層只存儲一次。即當前隊列中存在兩個點屬於同一層,除非在更新某個點的距離後重新進行BFS,否則不會再向某層的點增加新的點。

2.在BFS時記錄一組「pointer」,用於在DFS過程中從上次的返回點繼續搜索,而不是從起點開始搜索。這種操作雖然為線性,但是其作用顯然不及第一種優化(實際上第一種優化存在時間複雜度為O(n^2*m)的情況)。

3.使用最大流速度和一般的帶寬不同,所以可以頻繁的調整容量或者調整浮點數。最好還是針對不同的網路設置最適當的流媒體參數。

4.減弱其「最壞時間複雜度比某些演算法還不如」的不足之一:採用HLPP演算法

代碼示例:

struct node
{
    int v,f,nx;
}p[MAXM];

int head[MAXN],cur[MAXN],d[MAXN],cnt,n,m,S,T;

inline void add_edge(int u,int v,int f)
{
    p[++cnt]=(node){v,f,head[u]};
    head[u]=cnt;
    p[++cnt]=(node){u,0,head[v]};
    head[v]=cnt;
}

inline bool bfs()
{
    for(re int i=S;i<=T;++i)
        d[i]=-1,cur[i]=head[i];
    queue q;
    d[S]=0;
    q.push(S);
    while(q.size())
    {
        int u=q.front();
        q.pop();
        for(int i=head[u];i;i=p[i].nx)
        {
            int v=p[i].v,f=p[i].f;
            if(d[v]==-1&&f)
            {
                q.push(v);
                d[v]=d[u]+1;
                if(v==T)
                    return 1;
            }
        }
    }
    return 0;
}

inline int dfs(int u,int flow)
{
    if(u==T)
        return flow;
    int ret=flow;
    for(int i=cur[u];i&&ret;i=p[i].nx)
    {
        cur[u]=i;
        int v=p[i].v,f=p[i].f;
        if(d[v]==d[u]+1&&f)
        {
            int w=dfs(v,min(ret,f));
            p[i].f-=w;
            p[i^1].f+=w;
            ret-=w;
            if(!ret)
                break;
        }
    }
    if(ret==flow)
        d[u]=-2;
    return flow-ret;
}

inline int dinic()
{
    int ans=0;
    while(bfs())
        ans+=dfs(S,0x3f3f3f3f);
    return ans;
}

五、總結

Dinic演算法作為最大流演算法的一種,能夠在較優的時間內獲得最大網路流,應用廣泛。

在實戰中,Dinic演算法的時間複雜度也更有優勢,而且最壞時間複雜度相對更小。Dinic在實際的網路流應用中佔據相當重要的地位。

原創文章,作者:小藍,如若轉載,請註明出處:https://www.506064.com/zh-tw/n/196819.html

(0)
打賞 微信掃一掃 微信掃一掃 支付寶掃一掃 支付寶掃一掃
小藍的頭像小藍
上一篇 2024-12-03 13:26
下一篇 2024-12-03 13:26

相關推薦

  • 心形照片拼圖模板

    如何使用心形照片拼圖模板 一、模板介紹 心形照片拼圖模板是一種讓用戶可以將自己的照片拼接成一個心形的巧妙設計,每個照片都是一個拼圖塊,當所有的照片配合完成時,呈現出一個完整的心形。…

    編程 2025-04-29
  • 基尼係數Excel計算模板

    這篇文章將介紹基尼係數Excel計算模板,為大家詳細闡述如何使用Excel進行基尼係數的計算。 一、模板下載及導入 首先需要下載基尼係數的Excel計算模板,可以在Excel中通過…

    編程 2025-04-28
  • iCircuit文件電路模板

    iCircuit是一款允許用戶在移動設備上輕鬆創建、模擬和共享電路模板的應用程序。 iCircuit還允許您向其他用戶展示您的電路設計,並從其他人那裡獲取靈感和想法。在本文中,我們…

    編程 2025-04-27
  • Python寫Word模板簡介

    Python可以用來生成Word文檔,讓你可以自動化生成報表、合同、申請表等文檔。本文將從多個方面詳細介紹Python寫Word模板的方法和技巧。 一、Word模板的結構 要生成W…

    編程 2025-04-27
  • 神經網路代碼詳解

    神經網路作為一種人工智慧技術,被廣泛應用於語音識別、圖像識別、自然語言處理等領域。而神經網路的模型編寫,離不開代碼。本文將從多個方面詳細闡述神經網路模型編寫的代碼技術。 一、神經網…

    編程 2025-04-25
  • Linux sync詳解

    一、sync概述 sync是Linux中一個非常重要的命令,它可以將文件系統緩存中的內容,強制寫入磁碟中。在執行sync之前,所有的文件系統更新將不會立即寫入磁碟,而是先緩存在內存…

    編程 2025-04-25
  • 詳解eclipse設置

    一、安裝與基礎設置 1、下載eclipse並進行安裝。 2、打開eclipse,選擇對應的工作空間路徑。 File -> Switch Workspace -> [選擇…

    編程 2025-04-25
  • Python安裝OS庫詳解

    一、OS簡介 OS庫是Python標準庫的一部分,它提供了跨平台的操作系統功能,使得Python可以進行文件操作、進程管理、環境變數讀取等系統級操作。 OS庫中包含了大量的文件和目…

    編程 2025-04-25
  • git config user.name的詳解

    一、為什麼要使用git config user.name? git是一個非常流行的分散式版本控制系統,很多程序員都會用到它。在使用git commit提交代碼時,需要記錄commi…

    編程 2025-04-25
  • MPU6050工作原理詳解

    一、什麼是MPU6050 MPU6050是一種六軸慣性感測器,能夠同時測量加速度和角速度。它由三個感測器組成:一個三軸加速度計和一個三軸陀螺儀。這個組合提供了非常精細的姿態解算,其…

    編程 2025-04-25

發表回復

登錄後才能評論