1. 程式人生 > >[圖論]最大流介紹 Ford-Fulkerson演算法 鄰接表實現

[圖論]最大流介紹 Ford-Fulkerson演算法 鄰接表實現

這次來講最大流的相關問題,介紹圖上的網路流。網路流具有各種各樣的性質和應用,還有很多的變體,程式設計競賽當中也經常會出現相關題目。

先來看一個例子:

最大傳輸量
網路中有兩臺計算機st,現在想從s傳輸到t,該網路中一共有N臺計算機,其中一些計算機之間連有一條單項的通訊電纜,每條通訊電纜都有對應的1秒鐘所能傳輸的最大資料量。當其他計算機之間沒有資料傳輸時,在1s內最多可以傳輸多少資料到t

這裡寫圖片描述

把計算機當作頂點,把連結計算機的通訊電纜當作邊,就可以把這個網路當作一個有向圖來考慮了。圖中的每條邊eE,都有對應的最大可能的資料傳輸量c(e),這樣,就可以把問題轉為如下形式。

  • 記錄每條邊對應的實際資料傳輸量為f
    (e)
  • 傳輸量應該滿足如下限制: 0f(e)c(e)
  • 對任意 v{s,t} 都有 Σeξ(v)f(e)=Σeξ+(v)f(e),即資料在傳輸過程中既不會增加也不會減少,收到的量和發出去的量必須相等。
  • 目標是最大化從s發出的資料量Σeξ+(s)f(e)
    我們稱是的傳輸量最大的f為最大流,而求解最大流的問題稱為最大流問題。此外, 我們稱c為邊的容量,f為邊的流量,s為源點,t為匯點。那麼,這個問題應該如何求解呢?首先考慮下面的貪心演算法。
    1、找一條st的只經過f(e)<c(e) 的邊的路徑。
    2、如果不存在滿足條件的路徑,則結束演算法,否則,沿著該路徑儘可能地增加c
    (e)
    ,返回第一步。
    將該演算法運用於樣例,就得到了如下結果:

這裡寫圖片描述

這樣的結果是正確的嗎?事實上,如果採用以下的方案,可以得到更優的結果。顯然這個貪心演算法是不正確的。

這裡寫圖片描述

我們觀察兩者之間的流量之差,可以發現,後者的方案在1->2之間少了1Mbps,卻換來了s->2和1->3->5兩處的流量增加。事實上,就是將原先得到的流給退回去,從而得到了新的更大的流,將演算法進行如下改進:
1、只利用滿足f(e)<c(e)e 對應的反向邊 rev(e) ,尋找一條從 st 的路徑。
2、如果不存在滿足條件的路徑,則結束,否則,沿著該路徑儘可能地增加流,返回第一步。

struct edge{int to,cap,rev;};//終點、容量、反向邊

vector<edge> G[MAXV];//鄰接表
bool used[MAXV]; //dfs時要用到
//向圖中增加一條從s到t,容量為cap的邊
void add_edge(int from,int to,int cap)
{
    edge temp;
    temp.to = to;
    temp.cap = cap;
    temp.rev = G[to].size();
    G[from].push_back(temp);
    temp.to = from;
    temp.cap = 0,
    temp.rev = G[from].size()-1;
    G[to].push_back(temp);

}

int dfs(int v,int t,int f)
{
    if (v==t) return f;
    used[v] = true;
    for(int i = 0; i < G[v].size(); i++)
    {
        edge &e = G[v][i];
        if (!used[e.to] && e.cap > 0)
        {
            int d = dfs(e.to, t, min(f,e.cap));
            if (d>0)
            {
                e.cap -= d;
                G[e.to][e.rev].cap += d;
                return d;
            }
        }
    }
    return 0;
}

int max_flow(int s,int t)
{
    int flow = 0;
    for(;;)
    {
        memset(used,0,sizeof(used));
        int f = dfs(s,t,INF);
        if (f==0) return flow;
        flow += f;
    }
}

記最大流的流量為F,那麼Ford-Fulkerson演算法最多進行F次深度優先搜尋,所以其複雜度為O(F|E|)。不過,這是一個很鬆的上界,達到這種最壞複雜度的情況幾乎不存在。所以在多數情況下,即便通過估算得到的複雜度偏高,實際運用當中還是比較快的。

相關推薦

[]介紹 Ford-Fulkerson演算法 鄰接實現

這次來講最大流的相關問題,介紹圖上的網路流。網路流具有各種各樣的性質和應用,還有很多的變體,程式設計競賽當中也經常會出現相關題目。 先來看一個例子: 最大傳輸量 網路中有兩臺計算機s和t,現在想從s傳輸到t,該網路中一共有N臺計算機,其中一些計算機之間連有

Ford-Fulkerson演算法(C++實現

本文主要講解最大流問題的Ford-Fulkerson解法。可是說這是一種方法,而不是演算法,因為它包含具有不同執行時間的幾種實現。該方法依賴於三種重要思想:殘留網路,增廣路徑和割。 一、殘留網路 顧名思義,殘留網路是指給定網路和一個流,其對應還可以容納的流組成的網路。具體說來,就是假定一個網

hdu3549(網路流入門題-Ford-Fulkerson演算法)

網路流深入學習請戳這裡。 Ford-Fulkerson方法依賴於三種重要思想,這三個思想就是:殘留網路,增廣路徑和割。 Ford-Fulkerson方法是一種迭代的方法。開始時,對所有的u,v∈V

(Edmond Karp演算法

Edmond Karp演算法的大概思想: 反覆尋找源點s到匯點t之間的增廣路徑,若有,找出增廣路徑上每一段[容量-流量]的最小值delta,若無,則結束。 在尋找增廣路徑時,可以用BFS來找,並且更新殘留網路的值(涉及到反向邊)。 而找到delta後,則使最

問題——Ford-Fulkerson方法的java實現

使用的圖的資料結構是鄰邊雜湊表,見Graph原始碼。 package algorithm; import java.util.LinkedList; import java.util.List; import java.util.Queue; import

的匹配問題與問題(二)——問題Ford-Fulkerson方法

本篇承接上一篇文章,主要講解最大流問題的Ford-Fulkerson解法。可是說這是一種方法,而不是演算法,因為它包含具有不同執行時間的幾種實現。該方法依賴於三種重要思想:殘留網路,增廣路徑和割。本文將會詳細介紹這些內容,下一篇文章我們提供一種該方法的Java實現。 在介紹

Ford-Fulkerson方法詳解及實現

最大流問題常常出現在物流配送中,可以規約為以下的圖問題。最大流問題中,圖中兩個頂點之間不能同時存在一對相反方向的邊。 邊上的數字為該條邊的容量,即在該條邊上流過的量的上限值。最大流問題就是在滿足容量限制條件下,使從起點s到終點t的流量達到最大。在介紹解決最大流問題的For

刷題總結——太空飛行計劃(大權閉合子解決)

.com freopen static 出發 pre nbsp 資料 任務 代碼 題目: 題目描述 W 教授正在為國家航天中心計劃一系列的太空飛行。每次太空飛行可進行一系列商業性實驗而獲取利潤。現已確定了一個可供選擇的實驗集合 E={E1,E2,…,Em},和進行這些實驗

【網路24題】小路徑覆蓋問題-二分匹配/

傳送門:luogu P2764 最小路徑覆蓋問題 題解 結論: D A G

HDU3081:Marriage Match II (Floyd/並查集+二分匹配/(+二分))

Marriage Match II Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)Total Submission(s): 5469 &n

CODEFORCES:103E(二分匹配&

CODEFORCES 103E(二分圖匹配&最大流)參考:1. 題目E. Buying SetsThe Hexadecimal virus loves playing withnumber sets — intersecting them, uniting them.

-前置推送標籤方法

package com.data.struct; public class RelabelToFront { private Node[][]graphic; private Node s; private Node t; public RelabelToFr

POJ 1149 PIGS 建

col 表示 ems span 相同 scanf 分享 dinic pan 題意: 你m個豬圈以及每個豬圈裏原來有多少頭豬,先後給你n個人,每個人能打開某一些豬圈並且他們最多想買Ki頭豬,在每一個人買完後能將打開的豬圈中的豬順意分配在這次打開豬圈裏,在下一個人來之前 已打開

割】opencv中構建/小割的gcgraph.h原始碼解讀

本文對opencv中構建圖和最大流/最小割的原始碼進行解讀,添加了中文註釋 opencv中gcgraph.h原始碼(也許有些許改動),需要用的同學,可以新增.h標頭檔案,直接複製粘下面的程式碼 #include <vector> using namespa

-EdmondsKarp方法

package com.data.struct; public class EdmondsKarp { private Node[][]graphic; private Node s; private Node t; private NodeArrayQueu

的匹配問題與問題(六)——匈牙利演算法一種簡潔實現

這個演算法更為簡潔,也好理解。和維基百科上介紹的演算法思路是一致的。 求最大匹配的一種顯而易見的演算法是:先找出全部匹配,然後保留匹配數最多的。但是這個演算法的時間複雜度為邊數的指數級函式。因此,需要尋求一種更加高效的演算法。下面介紹用增廣路求最大匹配的方法(稱作匈牙

二分的基本概念+二分匹配問題(匈牙利演算法

       今天學了二分圖的最大匹配,其中的匈牙利演算法。。哦不,其實遠不止這個,還有後面的一系列KM、開花樹啊什麼的演算法。反正又是一個異常懵逼的一天。。。 我覺得應該是上課前沒有稍微預習一下這個演算法是什麼,瞭解個大概,導致上課總是老師講到後面了,我卻還在糾結前面的內

網路一·Ford-Fulkerson演算法

早在1955年,T.E.哈里斯就提出在一個給定的網路上尋求兩點間最大運輸量的問題。並且由此產生了一個新的圖論模型:網路流。 用數學的語言描述就是給定一個有向圖G=(V,E),其中每一條邊(u,v)均有一個非負數的容量值,記為c(u,v)≥0。同時在圖中有兩個特殊的頂點,源點S和匯點T。 舉個例子: 其中節

【網路問題Edmonds-Karp演算法

       實現最大流有好幾種演算法,比如Dinic或者ISAP演算法,Edmonds-Karp只是其中最好理解的一種演算法,它的實現要運用到增廣路與BFS,當然也可以用DFS,但效率太低。網路流這東西是用來求從s點到t點(起點為s,終點為t)的流量問題,因為類似網路資料傳

hdu1532EK與SAP演算法

EK是最樸素的最大流演算法了,但效率比較慢,當然程式碼也比較清晰,思路去看LRJ的白書就行了。 但是由於網上大牛總結SAP基本上是解決最大流的最標準模板了,  網上大牛說基本沒有什麼最大流能卡SAP。 EK程式碼: #include<iostream> #in