萌新瞎講網路流之最大流 不定期更新理解篇

2022-02-28 23:45:53 字數 4646 閱讀 1695

【不定期更新篇(未成形篇)】

一直在搞,就像吃很惡習的東西,好想吐;

但還是可以理解成良藥苦口啊~;

基礎知識定義:

網路是一種特殊的有向圖。

有向加權圖g,指定兩個定點s和t,分別稱為源和匯。邊上的權值稱為容量;

網路中的乙個可行流並不是改路線中所有邊的容量的簡單相加,這段路線的總承重量受路線中最小容量邊的制約。

尋找方案使得總運輸量最大,這就是網路流演算法需要解決的問題;

通俗的講:(我將說路就是管道,路的權值就是管道的容量)

在乙個網路中,往源點灌水,然後從源點水開始流向匯點,

【只考慮在單位時間下】

1.如果從大的流分流,分開的流的總和是小於這個流的,那麼支流的流量就是本身的容量,見下圖(1);

2.如果從小的流往大的容量的管道,那麼對於大的管道來說,水流過來才這麼點,所以大的管道也才只有之前的那麼多水而已啊,見圖(2);

乙個網路中的最大流就是指該網路中流值最大的流,只是指了某條特定的流,而我們是要通過方法來計算這個最大流的流值是多大。

感覺先搞一下網路流演算法ek演算法的流程好像還是不懂,真的好無力啊。

可以先打一遍!!!(推薦);

大致流程就是bfs一下,找到一條增廣路,搞出乙個最小的流值,從源到匯上的路的權值減去這個流值,並且在匯到源上權值加上這個流值;

ff方法的具體步驟(摘自圖論書):

(1):

初始化網路中所有邊的容量,c繼承該邊的容量,c初始化為0,其中邊即為回退邊。初始化最大流為0;

(2):

在殘留網路中找出一條從源s到匯t的增廣路p。如果能找到,則轉步驟(3);

如不能找到,則轉步驟(5).

(3):在增廣路p中找出所謂的「瓶頸」邊,即路徑中容量最小的邊,記錄下這個值x,並且累加到最大流中,轉步驟(4)。

(4):將增廣路中所有c< u , v >減去x,所有c加上x,構成新的殘留網路。轉步驟(2).

(5):得到網路的最大流,退出。

const intn=110;      //最大點個數

intma[n][n],n,p[n]; //ma:鄰接陣列;n:點數;p:前驅陣列

bool ek_bfs()}}

return false;}

int ek()

ans+=mm; //累加進最大流

u=m;

while(p[u]!=-1) //修改路徑上邊的容量;

}return ans;

}

感覺打完了一發。。。還是好難理解是不是,模擬一發吧。。。

原題鏈結(

給你4個點,5條邊;

5 4
1 2 40//代表1到2有40的容量
1 4 20
2 4 20
2 3 30
3 4 10
然後模擬(我就記錄個flow的結果,細節上的自行模擬了…)
一開始進去:
初始化,
從源 1 開始,
1->2,flow[2]=40;  2入隊;
1->4,flow[4]=20;  4入隊;
2->3,flow[3]=min(flow[2],ma[2][3])=20;
2->4,不需要,4已經處理過了
4出隊=匯點,返回;
然後回溯一下:找到乙個最小的流,然後更新,將找到的增廣路把這個殘留網路額外的流減去,反向邊加上這個值
……
一直迴圈到找不到增廣路為止;
可惜。。。真心好難理解啊。。打完還是似懂非懂,其實最重要的兩步就是bfs找增廣路,然後構造一下殘留網路,一直迴圈,然後直到找不到增廣路,當前的流值,就是最大流;

然後理解dinic演算法,推薦:

comzyh的部落格

基本流程:

1.根據殘留網路計算層次圖;

2.在層次圖中使用dfs進行增廣直到不存在增廣路

3.重複以上步驟直到無法增廣

--------補充說明乙個找增廣的問題;

給出這樣一副圖:

先找到的增廣有:

路      流量     轉化成    路   流量    路   流量

1->2     2                    12   0

2->4     2                    44   0

4->6     2                    66   0

ok,這樣就是找到乙個完全的增廣;ans+=2;

繼續;1->3     1                    33   0

3->4     1                    44   0

4->2     2                    2->4    1     4->2   1

2->5     1                    5->2    1     2->5   0

5->6     1                    6->5    1     5->6   0

ok,又是乙個增廣 ;ans+=1;

終點闡述反向弧的作用:

反向弧可以理解我給這條路分配了x的流量,我建立乙個反向弧,等下給自己乙個後悔的機會。

比如上面那個第一次找增廣過程中4->2建立反向弧,在第二次找增廣的時候利用了這個反向弧;

我們可以理解之前我先安排2單位水通過這條路,不要理解成是這條路給的流量,流量都是從源點出發的,很自然這條路上的流量是上面那條路的流量流過來。

對於第一次,留多少呢,我先流個2吧,然後給自己乙個機會(建立乙個反向弧),等會可能我往這個方向不流2,比如第二次找到了,我可以去別的方向流1,那多個機會流還不好啊,形象上的理解就是上面那個點出來的分流了;

那麼還有乙個問題,怎麼理解反向弧前面的那些路呢?

是不是可以理解這條路(3->4)的流能到達路(2->4)到達4這個點,然而4以後已經阻斷了,或者說已經塞了一部分流量了,

然後呢可以利用路(2->4)的反向弧(4->2),索取一部分他的,後悔以後就是說前面那個點(2)在這裡分流了,注意每次找的增廣都是乙個能實現的圖上的乙個"瓶頸",

然後點(2)分流,實際上是給路(2->5)1單位,給路(2->4)1單位,然後路(3->4)往點4運了1單位,4->6流向6就是2單位;

貼一發dinic的模板;

鄰接矩陣版本:

const int inf=0x3f3f3f3f;

const int n=1e3+10;

int ma[n][n];

int dis[n];

int q[n*100],h,r;

int n,m,ans;

bool bfs()}}

if(dis[n]>0)

return true;

return false;

}int dfs(int x,int low)

}return 0;

}void dinic()

printf("%d\n",ans);

}

前向星版本:hdu(3549)

#includeusing namespace std;

typedef __int64 ll;

const int inf=0x3f3f3f3f;

const int n=2050;

int level[n];

int q[n],h;

int n,m,ans;

struct asd;

asd edge[2500000];

int head[2500000],tol;

bool bfs(int s,int t)}}

return false;

}int dfs(int now,int maxw,int t)

}return ret;

}void dinic()

void add(int a,int b,int c)

int main()

printf("case %d: ",cas++);

dinic();

}return 0;

}

後悔的就是原來分流,新流往原來的路走。。。好好理解吧。。。。也求乙個好理解的idea!

網路流之最大流

網路流之最大流 一 問題引入。有n個排水口,不同的排水口之間有m條水管連線,水一開始從源點s流出,最終到達t。每條邊 水管 都有乙個最大的流量。除了s,t外,每個排水口的流入量都要等於流出量,詢問最多能有多少水到達終點t 如圖所示 即poj 1273 可以將問題進行如下整理 1 用c e 表示每條邊...

網路流之最大流

因為網上介紹網路流和最大流理論的文章非常的多,也都解釋的非常清晰並附帶 再加上繪圖技術不佳,語文表達極差,就只講解一下程式實現部分。想看理論講解及演算法正確性證明的讀者可以上網搜一搜,這裡推薦一篇部落格,鏈結如下 那麼,既然網上的資源那麼多,為什麼還要寫這篇部落格呢?一是為了湊數做筆記,二是網上的許...

網路流之 最大流

最大流演算法是網路流中基礎的演算法,解決的方法有很多,比如ek,dinic,sap等等,在這裡介紹一下ek演算法。從源點s開始廣度優先尋找一條到t的路徑,計算出這條路徑的最大流量 短板效應 l,回溯,將這條路徑的每條邊的最大流量減去l,然後新增反向邊,容量為l,網路流的最大流max l。當找不到從s...