㈠ pascal 網路流是什麼啊
網路流是一種模型。由源點、匯點、中間點構成。從原點要流一些東西通過中間節點到匯點。其中每兩個點之間有一條邊,每條邊有一定的容量,流的東西不能超過邊的容量。
泛化成現實生活中的一個例子,就是水廠要送一定水到你家,水要經過很多管子,求最多能送多少水到你家。首先從水廠為你家流出的水一定等於流到你家的水(不然水會無故消失嗎?)。其次每根管道流的水不能超過管子的容量(不然就爆了)。這就涉及到一個求最大流的問題。一般演算法為EK,2F,sap,Dinic,各種預留推進……
因此網路流是一個在生活中很有用的東西,不過NOIP不會考。
附網路流圖:
㈡ 高分:網路流問題
一、引言
網路流演算法是一種高效實用的演算法,相對於其它圖論演算法來說,它的模型更加復雜,編程復雜度也更高。但是它綜合了圖論中的其它一些演算法(如最短路徑、寬度搜索演算法),因而適用范圍也更廣,經常能夠很好地解決一些搜索與動態規劃無法解決的非np問題。
網路流在具體問題中的應用,最具挑戰性的部分是模型的構造,它沒用現成的模式可以套用,需要我們對各種網路流的性質了如指掌(比如點有容量、容量有上下限、多重邊等等),根據具體的問題發揮我們的創造性。一道問題經常可以建立多種模型,不同的模型對問題的解決效率的影響也是不同的,本文通過實例探討如何確定適當的模型,提高網路流演算法的效率。
二、網路流演算法時間效率
當我們確定問題可以使用最大流演算法求解後,就根據常用的ford-fulkerson標號法求解;而最小(大)費用最大流問題也可用類似標號法的對偶演算法解題。ford-fulkerson標號法的運行時間為o(ve2),對偶法求最小費用流的運行時間大約為o(v3e2)。
顯然,影響網路流演算法的時間效率的因素主要是網路中頂點的數目與邊的數目。這二個因素之間不是相互獨立的,而是相互聯系,矛盾而統一的。在構造網路模型中,有時,實現了某個因素的優化,另外一個因素也隨之得到了優化;有時,實現某個因素的優化卻要以增大另一因素為代價。因此,我們在具體問題的解決中,要堅持"全局觀",實現二者的平衡。
三、模型的優化與選擇
(一)減少模型的頂點數與邊數,優化模型
如果能根據問題的一些特殊性質,減少網路模型中的頂點的數目和邊的數目,則可以大大提高演算法的效率。
例1:最少皇後控制
在國際象棋中,皇後能向八個方向攻擊(如圖1(a)所示,圖中黑點格子為皇後的位置,標有k的格子為皇後可攻擊到的格子)。現在給定一個m*n(n、m均不大於於50)的棋盤,棋盤上某些格子有障礙。每個皇後被放置在無障礙的格子中,它就控制了這個格子,除此,它可以從它能攻擊到的最多8個格子中選一個格子來控制,如圖1(b)所示,標號為1的格子被一個皇後所控制。
請你編一程序,計算出至少有多少個皇後才能完全控制整個棋盤。
圖1(a) 圖1(b)
輸入格式:
輸入文件的第一行有兩個整數m和n,表示棋盤的行數與列數。接下來m行n列為一個字元矩陣,用''.''號表示空白的格子,''x''表示有障礙的格子。
輸出格式:
輸出文件的第一行僅有一個數s,表示需要皇後的數目。
sample input
3 4
x...
x.x.
.x..
sample ouput
5
問題分析]
如果本問題用簡單的搜索來做,由於題目給的棋盤很大,搜索演算法很難在短時間內出解。由於一個皇後在棋盤最多隻能控制兩個格子,因此最少需要的皇後數目的下界為[n*m/2]。要使得皇後數目最少,必定是盡量多的皇後控制兩個格子。如果我們在每兩個能相互攻擊到的格子之間加上一條有向弧,則問題很類似於二分圖的最大匹配問題。
[模型一]
1. 將每個非障礙的格子按行優先編號(0~m*n-1)。
2. 將上述的每個格子i折成兩個格子i''和i'''',作為網路模型中的頂點。
3. 若格子i可以攻擊到格子j且i<j,則在模型中頂點i''到j''''之間加上一條有向弧,容量為1。
4. 增加一個源點s,從s點向所有頂點i''添上一條弧;增加一個匯點t,從所有頂點j''''到t添上一條弧,容量均為1。
圖1(b)所示的棋盤,對應的模型為:
圖2
顯然,任一解對應於以上模型的一個最大匹配。且最大匹配中,匹配數必定是偶數。因此至少需要的馬匹數為m*n-障礙數-最大匹配數/2。
[模型二]
如果我們將棋盤塗成黑白相間的格子,則某皇後控制的兩個格子一定是一個是黑格,另一個是白格(如圖3),不妨設這兩個格子中皇後在白格子上。於是,我們將n*m個格子分成兩部分白格與黑格。因此我們可以將模型一優化為:
圖3
1.將棋盤中的所有格子分成兩個部分,對所有的格子進行編號,每個白格與它能攻擊到的黑格之間(障礙除外)添上一條從白格到黑格的弧,構成一個二分圖。
2.增加一個源點s,從s點向所有非障礙的白格添上一條弧;增加一個匯點t,從所有非障礙的黑格到t添上一條弧。
3.設置所有的弧的流量為1。
圖1(b)所示的棋盤,對應的模型為:
圖4
[兩種模型的比較]
顯然,模型二的頂點數與邊數大致是模型一的一半。下面是在bp環境下兩種模型的時間效率比較(p166/32m):
模型一 模型二
可擴展性 不易列印出一種解 容易列印出一種解
模型二正是根據問題的特殊性(即馬的走法),將網格中的格點分成白與黑兩類,且規定馬只能從白格跳到黑格,從而避免將每個格點折分成兩個點,減少模型的頂點數,同時也大大減少了邊的數目。達到了很好的優化效果。
(二)綜合各種模型的優點,智能選擇模型
有時,同一問題的各種模型各有特色,各有利弊。這種情況下,我們就要綜合考慮各種模型的優缺點,根據測試數據智能地選擇問題的模型。
例2火星探測器(ioi97)
有一個登陸艙(pod),里邊裝有許多障礙物探測車(mev),將在火星表面著陸。著陸後,探測車離開登陸艙向相距不遠的先期到達的傳送器(transmitter)移動,mev一邊移動,一邊採集岩石(rock)標品,岩石由第一個訪問到它的mev所採集,每塊岩石只能被採集一次。但是這之後,其他mev可以從該處通過。探測車mev不能通過有障礙的地面。
本題限定探測車mev只能沿著格子向南或向東從登陸處向傳送器transmitter移動,允許多個探測車mev在同一時間占據同一位置。
任務:計算出所有探測車的移動途徑,使其送到傳送器的岩石標本的數量最多,且使得所有的探測車都必須到達傳送器。
輸入:
火星表面上的登陸艙pod和傳送器之間的位置用網路p和q表示,登陸艙pod的位置為(1,1)點,傳送器的位置在(p,q)點。
火星上的不同表面用三種不同的數字元號來表示:
0代表平坦無障礙
1代表障礙
2代表石塊。
輸入文件的組成如下:
numberofvehicles
p
q
(x1y1)(x2y1)(x3,y1)…(xp-1y1)(xpy1)
(x1y2)(x2y2)(x3,y2)…(xp-1y1)(xpy2)
(x1y3)(x2y3)(x3,y3)…(xp-1y3)(xpy3)
…
(x1yq-1)(x2yq-1)(x3,yq-1)…(xp-1yq-1)(xpyq-1)
(x1yq)(x2yq)(x3,yq)…(xp-1yq)(xpyq)
p和q是網路的大小;numberofvehicles是小於1000的整數,表示由登陸艙pod所開出的探測車的個數。共有q行數據,每行表示火星表面的一組數據,p和q都不超過128。
[模型一]
很自然我們以登陸艙的位置為源點,傳送器的位置為匯點。同時某塊岩石由第一個訪問到它的mev所採集,每塊岩石只能被採集一次。但是這之後,其他mev可以從該處通過,且允許多個探測車mev在同一時間占據同一位置。因此我們將地圖中的每個點分成兩個點,即(x,y)à(x,y,0)和(x,y,1)。具體的描述一個火星地圖的網路模型構造如下:
1. 將網格中的每個非障礙點分成(x,y)兩個點(x,y,0)和(x,y,1),其中源點s = v(1, 1, 0),匯點t = v(maxx, maxy, 1)。
2. 在以上頂點中添加以下三種類型的邊e1,e2,e3,相應地容量和費用分別記為c1、c2、c3以及w1、w2、w3:
u e1 = v(x, y, 0) -> v(x, y, 1),c1 = maxint,w1 = 0。
u e2 = v(x, y, 0) -> v(x, y, 1),c2 = 1,w2 = -1(這里要求(x, y)必須是礦石)
u e3 = v(x, y, 1) -> v(x'', y'', 0),c3 = maxint,w3 = 0.
其中x''=x+1 y''=y 或x''=x y''=y+1,1 <= x'' <= maxx,1 <= y'' <= maxy,且(x'' y'')非障礙。
從以上模型中可以看出,在構造的過程中,將地圖上的一個點"拆"成了網路的兩個節點。添加e1型邊使得每個點可以被多次訪問,而添加e2型邊使得某點上的礦石對於這個網路,從s到t的一條路徑可以看作是一輛探測車的行動路線。路徑費用就是探測車搜集到的礦石的數目。對於網路g求流量為numberofvehicles的固定最小費用流,可以得到問題的解。
[模型二]
事實上,如果我們只考慮這numberofvehicles輛車中每輛車分別依次裝上哪些礦石。則每輛車經過的礦石就是一條流,因此我們以網格中的礦石為網路的頂點建立以下的網路流模型。
1. 將網格中的每個起點(網格左上角)能到達,且能從它能到達終點(右下角)的礦石 (x,y)點分成左點(x,y,0)和右點(x,y,1)兩個點,並添加源點s和匯點t。
2. 在以上頂點中添加以下五種類型的邊e1,e2,e3,相應地容量和費用分別記為c1、c2、c3以及w1、w2、w3:
u e1 = v(x, y, 0) -> v(x, y, 1),c1 = 1,w1 = -1。
u e2 = v(x, y, 1) -> v(x'', y'', 0),c2 = 1,w2 = 0(礦石點(x, y)可到達礦石點(x'',y''))。
u e3 = s -> v(x, y, 0),c3 = 1,w3 = 0。
u e4 = v(x, y, 1)->t,c4 = 1,w4 = 0。
u e5=s->t,c5=maxint,w5=0。
由於每個石塊被折成兩個點,且容量為1,就保證了每個石塊只被取走一次,同時取走一塊石塊就得到-1的費用。因此對以上模型,我們求流量為numberofvehicles的最小費用流,就可得到解。
[兩種模型的比較]
1.模型一以網格為頂點,模型二以礦石為頂點,因此在頂點個數上模型二明顯優於模型一,對於一些礦石比較稀疏,而網格又比較大的數據,模型二的效率要比模型一來得高。且只要礦石的個數不超過一定數目,模型二可以處理p,q很大的數據,而模型一卻不行。
2.模型一中邊的數目最多為3*p*q,而模型二中邊的數目最壞情況下大約為p*q*(p+1)*(q+1)/4-p*q。因此在這個問題中,若對於一些礦石比較密集且網格又比較大的數據,模型二的邊數將大大超過模型一,從而使得時間效率大大低於模型一。
下面是網格中都是礦石的情況比較(piii700/128m ,bp7.0保護模式):
numberofvehicles=10 模型一 模型二
通過以上數據,可知對於p,q不超過60的情況,模型一都能在10秒內出解。而模型二則對於p、q=30的最壞情況下速度就很慢了,且p、q超過30後就出現內存溢出情況,而無法解決。
因此,對於本題,以上兩種模型各有利弊,我們可根據測試數據中礦石稀疏程度來決定建立什麼樣的模型。若礦石比較稀疏,則可以考慮用建立如模型二的網路模型;若礦石比較密集則建立模型一所示網路模型。然後,再應用求最小費用最大流演算法求解。對於p,q>60,且礦石比較多情況下,兩種模型的網路流演算法都無法求解。在實際的應用中問題經常都只要求近似解,此時還可用綜合一些其它演算法來求解。
四、結束語
綜上所述,網路流演算法中模型的優化是網路流演算法提高效率的根本。我們要根據實際問題,從減少頂點及邊的角度綜合考慮如何對模型進行優化,選擇適當的模型,以提高演算法的效率。對於有些題目,解題的各種模型各有優劣時,還可通過程序自動分析測試數據,以決定何種情況下採用何種模型,充分發揮各種模型的優點,以達到優化程序效率的目的。
㈢ 網路流的最大流演算法
1、augment path,直譯為「增廣路徑」,其思想大致如下:
原有網路為G,設有一輔助圖G',其定義為V(G') = V(G),E(G')初始值(也就是容量)與E(G)相同。每次操作時從Source點搜索出一條到Sink點的路徑,然後將該路徑上所有的容量減去該路徑上容量的最小值,然後對路徑上每一條邊<u,v>添加或擴大反方向的容量,大小就是剛才減去的容量。一直到沒有路為止。此時輔助圖上的正向流就是最大流。
我們很容易覺得這個演算法會陷入死循環,但事實上不是這樣的。我們只需要注意到每次網路中由Source到Sink的流都增加了,若容量都是整數,則這個演算法必然會結束。
尋找通路的時候可以用DFS,BFS最短路等演算法。就這兩者來說,BFS要比DFS快得多,但是編碼量也會相應上一個數量級。
增廣路方法可以解決最大流問題,然而它有一個不可避免的缺陷,就是在極端情況下每次只能將流擴大1(假設容量、流為整數),這樣會造成性能上的很大問題,解決這個問題有一個復雜得多的演算法,就是預推進演算法。
2、push label,直譯為「預推進」演算法。
3、壓入與重標記(Push-Relabel)演算法
除了用各種方法在剩餘網路中不斷找增廣路(augmenting)的Ford-Fulkerson系的演算法外,還有一種求最大流的演算法被稱為壓入與重標記(Push-Relabel)演算法。它的基本操作有:壓入,作用於一條邊,將邊的始點的預流盡可能多的壓向終點;重標記,作用於一個點,將它的高度(也就是label)設為所有鄰接點的高度的最小值加一。Push-Relabel系的演算法普遍要比Ford-Fulkerson系的演算法快,但是缺點是相對難以理解。
Relabel-to-Front使用一個鏈表保存溢出頂點,用Discharge操作不斷使溢出頂點不再溢出。Discharge的操作過程是:若找不到可被壓入的臨邊,則重標記,否則對臨邊壓入,直至點不再溢出。演算法的主過程是:首先將源點出發的所有邊充滿,然後將除源和匯外的所有頂點保存在一個鏈表裡,從鏈表頭開始進行Discharge,如果完成後頂點的高度有所增加,則將這個頂點置於鏈表的頭部,對下一個頂點開始Discharge。
Relabel-to-Front演算法的時間復雜度是O(V^3),還有一個叫Highest Label Preflow Push的演算法復雜度據說是O(V^2*E^0.5)。我研究了一下HLPP,感覺它和Relabel-to-Front本質上沒有區別,因為Relabel-to-Front每次前移的都是高度最高的頂點,所以也相當於每次選擇最高的標號進行更新。還有一個感覺也會很好實現的演算法是使用隊列維護溢出頂點,每次對pop出來的頂點discharge,出現了新的溢出頂點時入隊。
Push-Relabel類的演算法有一個名為gap heuristic的優化,就是當存在一個整數0<k<V,沒有任何頂點滿足h[v]=k時,對所有h[v]>k的頂點v做更新,若它小於V+1就置為V+1。
cpp程序: #include<cstdio>#include<cstring>#include<algorithm>#include<queue>#;inttt,kase;intnn,m;intH[45],X[1004],P[1004],flow[1004],tot,cap[1005];intd[45];intS,T;voidadd(intx,inty,intz){P[++tot]=y;X[tot]=H[x];H[x]=tot;flow[tot]=z;cap[tot]=flow[tot];}queue<int>q;boolbfs(){memset(d,0,sizeof(d));d[S]=1;intx;q.push(S);while(!q.empty()){x=q.front();q.pop();for(inti=H[x];i;i=X[i]){if(flow[i]>0&&!d[P[i]]){d[P[i]]=d[x]+1;q.push(P[i]);}}}returnd[T];}intdfs(intx,inta){if(x==T||a==0)returna;intf=a,tmp;for(inti=H[x];i;i=X[i]){if(flow[i]>0&&d[P[i]]==d[x]+1){tmp=dfs(P[i],min(flow[i],a));flow[i]-=tmp;a-=tmp;flow[i^1]+=tmp;if(!a)break;}}if(f==a)d[x]=-1;returnf-a;}intDinic(){intf=0;while(bfs())f+=dfs(S,inf);returnf;}intmain(){/**輸入過程省略**/intmaxflow=Dinic();printf(%d
,maxflow);return0;}
㈣ 我知道SAP解決無重邊的網路流的方法。如果有重邊怎麼辦
拆點的說。。。
㈤ 網路流的資料
編輯本段定義
圖論中的一種理論與方法,研究網路上的一類最優化問題 。1955年 ,T.E. 哈里斯在研究鐵路最大通量時首先提出在一個給定的網路上尋求兩點間最大運輸量的問題。1956年,L.R. 福特和 D.R. 富爾克森等人給出了解決這類問題的演算法,從而建立了網路流理論。所謂網路或容量網路指的是一個連通的賦權有向圖 D= (V、E、C) , 其中V 是該圖的頂點集,E是有向邊(即弧)集,C是弧上的容量。此外頂點集中包括一個起點和一個終點。網路上的流就是由起點流向終點的可行流,這是定義在網路上的非負函數,它一方面受到容量的限制,另一方面除去起點和終點以外,在所有中途點要求保持流入量和流出量是平衡的。如果把下圖看作一個公路網,頂點v1…v6表示6座城鎮,每條邊上的權數表示兩城鎮間的公路長度。現在要問 :若從起點v1將物資運送到終點v6去 ,應選擇那條路線才能使總運輸距離最短�這樣一類問題稱為最短路問題 。 如果把上圖看作一個輸油管道網 , v1 表示發送點,v6表示接收點,其他點表示中轉站 ,各邊的權數表示該段管道的最大輸送量。現在要問怎樣安排輸油線路才能使從v1到v6的總運輸量為最大。這樣的問題稱為最大流問題。
最大流理論是由福特和富爾克森於 1956 年創立的 ,他們指出最大流的流值等於最小割(截集)的容量這個重要的事實,並根據這一原理設計了用標號法求最大流的方法,後來又有人加以改進,使得求解最大流的方法更加豐富和完善 。最大流問題的研究密切了圖論和運籌學,特別是與線性規劃的聯系,開辟了圖論應用的新途徑。
目前網路流的理論和應用在不斷發展,出現了具有增益的流、多終端流、多商品流以及網路流的分解與合成等新課題。網路流的應用已遍及通訊、運輸、電力、工程規劃、任務分派、設備更新以及計算機輔助設計等眾多領域。
網路流演算法
一、網路流的基本概念
先來看一個實例。
現在想將一些物資從S運抵T,必須經過一些中轉站。連接中轉站的是公路,每條公路都有最大運載量。如下圖:
每條弧代表一條公路,弧上的數表示該公路的最大運載量。最多能將多少貨物從S運抵T?
這是一個典型的網路流模型。為了解答此題,我們先了解網路流的有關定義和概念。
若有向圖G=(V,E)滿足下列條件:
1、 有且僅有一個頂點S,它的入度為零,即d-(S) = 0,這個頂點S便稱為源點,或稱為發點。
2、 有且僅有一個頂點T,它的出度為零,即d+(T) = 0,這個頂點T便稱為匯點,或稱為收點。
3、 每一條弧都有非負數,叫做該邊的容量。邊(vi, vj)的容量用cij表示。
則稱之為網路流圖,記為G = (V, E, C)
譬如圖5-1就是一個網路流圖。
1.可行流
對於網路流圖G,每一條弧(i,j)都給定一個非負數fij,這一組數滿足下列三條件時稱為這網路的可行流,用f表示它。
1、 每一條弧(i,j)有fij≤cij。
2、 除源點S和匯點T以外的所有的點vi,恆有:
該等式說明中間點vi的流量守恆,輸入與輸出量相等。
3、 對於源點S和匯點T有:
這里V(f)表示該可行流f的流量。
例如對圖5-1而言,它的一個可行流如下:
流量V(f) = 5。
2.可改進路
給定一個可行流f=。若fij = cij,稱<vi, vj>為飽和弧;否則稱<vi, vj>為非飽和弧。若fij = 0,稱<vi, vj>為零流弧;否則稱<vi, vj>為非零流弧。
定義一條道路P,起點是S、終點是T。把P上所有與P方向一致的弧定義為正向弧,正向弧的全體記為P+;把P上所有與P方向相悖的弧定義為反向弧,反向弧的全體記為P-。
譬如在圖5-1中,P = (S, V1, V2, V3, V4, T),那麼
P+ = {<S, V1>, <V1, V2>, <V2, V3>, <V4, T>}
P- = {<V4, V3>}
給定一個可行流f,P是從S到T的一條道路,如果滿足:
那麼就稱P是f的一條可改進路。(有些書上又稱:可增廣軌)之所以稱作「可改進」,是因為可改進路上弧的流量通過一定的規則修改,可以令整個流量放大。具體方法下一節會重點介紹,此不贅述。
3.割切
要解決網路最大流問題,必須先學習割切的概念和有關知識。
G = (V, E, C)是已知的網路流圖,設U是V的一個子集,W = V\U,滿足S U,T W。即U、W把V分成兩個不相交的集合,且源點和匯點分屬不同的集合。
對於弧尾在U,弧頭在W的弧所構成的集合稱之為割切,用(U,W)表示。把割切(U,W)中所有弧的容量之和叫做此割切的容量,記為C(U,W),即:
例如圖5-1中,令U = {S, V1},則W = {V2, V3, V4, T},那麼
C(U, W) = <S, V2> + <V1, V2> + <V1, V3>+<V1, V4>=8+4+4+1=17
定理:對於已知的網路流圖,設任意一可行流為f,任意一割切為(U, W),必有:V(f) ≤ C(U, W)。
通俗簡明的講:「最大流小於等於最小割」。這是「流理論」里最基礎最重要的定理。整個「流」的理論系統都是在這個定理上建立起來的,必須特別重視。
下面我們給出證明。
網路流、可改進路、割切都是基礎的概念,應該扎實掌握。它們三者之間乍一看似乎風馬牛不相干,其實內在聯系是十分緊密的。
二、求最大流
何謂最大流?首先它必須是一個可行流;其次,它的流量必須達到最大。這樣的流就稱為最大流。譬如對圖5-1而言,它的最大流如下:
下面探討如何求得最大流。
在定義「可改進路」概念時,提到可以通過一定規則修改「可改進路」上弧的流量,可以使得總流量放大。下面我們就具體看一看是什麼「規則」。
對可改進路P上的弧<vi, vj>,分為兩種情況討論:
第一種情況:<vi, vj>∈P+,可以令fij增加一個常數delta。必須滿足fij + delta ≤ cij,即delta ≤ cij – fij。
第二種情況:<vi, vj>∈P-,可以令fij減少一個常數delta。必須滿足fij - delta ≥ 0,即delta ≤ fij
根據以上分析可以得出delta的計算公式:
因為P+的每條弧都是非飽和弧,P-的每條弧都是非零流弧,所以delta > 0。
容易證明,按照如此規則修正流量,既可以使所有中間點都滿足「流量守恆」(即輸入量等於輸出量),又可以使得總的流量有所增加(因為delta > 0)。
因此我們對於任意的可行流f,只要在f中能找到可改進路,那麼必然可以將f改造成為流量更大的一個可行流。我們要求的是最大流,現在的問題是:倘若在f中找不到可改進路,是不是f就一定是最大流呢?
答案是肯定的。下面我們給出證明。
定理1 可行流f是最大流的充分必要條件是:f中不存在可改進路。
證明:
首先證明必要性:已知最大流f,求證f中不存在可改進路。
若最大流f中存在可改進路P,那麼可以根據一定規則(詳見上文)修改P中弧的流量。可以將f的流量放大,這與f是最大流矛盾。故必要性得證。
再證明充分性:已知流f,並且f中不存在可改進路,求證f是最大流。
我們定義頂點集合U, W如下:
(a) S∈U,
(b) 若x∈U,且fxy<cxy,則y∈U;
若x∈U,且fyx>0,則y∈U。
(這實際上就是可改進路的構造規則)
(c) W = V \ U。
由於f中不存在可改進路,所以T∈W;又S∈U,所以U、W是一個割切(U, W)。
按照U的定義,若x∈U,y∈W,則fxy = cxy。若x∈W,y∈U,則fxy = 0。
所以,
又因 v(f)≤C(U,W)
所以f是最大流。得證。
根據充分性證明中的有關結論,我們可以得到另外一條重要定理:
最大流最小割定理:最大流等於最小割,即max V(f) = min C(U, W)。
至此,我們可以輕松設計出求最大流的演算法:
step 1. 令所有弧的流量為0,從而構造一個流量為0的可行流f(稱作零流)。
step 2. 若f中找不到可改進路則轉step 5;否則找到任意一條可改進路P。
step 3. 根據P求delta。
step 4. 以delta為改進量,更新可行流f。轉step 2。
step 5. 演算法結束。此時的f即為最大流。
三、最小費用最大流
1.問題的模型
流最重要的應用是盡可能多的分流物資,這也就是我們已經研究過的最大流問題。然而實際生活中,最大配置方案肯定不止一種,一旦有了選擇的餘地,費用的因素就自然參與到決策中來。
圖5-8是一個最簡單的例子:弧上標的兩個數字第一個是容量,第二個是費用。這里的費用是單位流量的花費,譬如fs1=4,所需花費為3*4=12。
容易看出,此圖的最大流(流量是8)為:fs1 = f1t = 5, fs2 = f2t = 3。所以它的費用是:3*5+4*5+7*3+2*3 = 62。
一般的,設有帶費用的網路流圖G = (V, E, C, W),每條弧<Vi, Vj>對應兩個非負整數Cij、Wij,表示該弧的容量和費用。若流f滿足:
(a) 流量V(f)最大。
(b) 滿足a的前提下,流的費用Cost(f) = 最小。
就稱f是網路流圖G的最小費用最大流。
2.演算法設計
我們模仿求最大流的演算法,找可改進路來求最小費用最大流。
設P是流f的可改進路,定義 為P的費用(為什麼如此定義?)。如果P是關於f的可改進路中費用最小的,就稱P是f的最小費用可改進路。
求最小費用最大流的基本思想是貪心法。即:對於流f,每次選擇最小費用可改進路進行改進,直到不存在可改進路為止。這樣的得到的最大流必然是費用最小的。
演算法可描述為:
step 1. 令f為零流。
step 2. 若無可改進路,轉step 5;否則找到最小費用可改進路,設為P。
step 3. 根據P求delta(改進量)。
step 4. 放大f。轉step 2。
step 5. 演算法結束。此時的f即最小費用最大流。
至於演算法的正確性,可以從理論上證明。讀者可自己思考或查閱有關運籌學資料。
2.最小費用可改進路的求解
求「最小費用可改進路」是求最小費用最大流演算法的關鍵之所在,下面我們探討求解的方法。
設帶費用的網路流圖G = (V, E, C, W),它的一個可行流是f。我們構造帶權有向圖B = (V』, E』),其中:
1、 V』 = V。
2、 若<Vi, Vj>∈E,fij<Cij,那麼<Vi, Vj>∈E』,權為Wij。
若<Vi, Vj>∈E,fij>0,那麼<Vj, Vi>∈E』,權為-Wij。
顯然,B中從S到T的每一條道路都對應關於f的一條可改進路;反之,關於f的每條可改進路也能對應B中從S到T的一條路徑。即兩者存在一一映射的邏輯關系。
故若B中不存在從S到T的路徑,則f必然沒有可改進路;不然,B中從S到T的最短路徑即為f的最小費用可改進路。
現在的問題變成:給定帶權有向圖B = (V』, E』),求從S到T的一條最短路徑。
考慮到圖中存在權值為負數的弧,不能採用Dijkstra演算法;Floyd演算法的效率又不盡如人意——所以,這里採用一種折衷的演算法:迭代法。
設Short[k]表示從S到k頂點的最短路徑長度;從S到頂點k的最短路徑中,頂點k的前趨記為Last[k]。那麼迭代演算法描述如下:(為了便於描述,令n = |V』|,S的編號為0,T的編號為n+1)
step 1. 令Short[k] +∞(1≤k≤n+1),Short[0] 0。
step 2. 遍歷每一條弧<Vk, Vj>。若Short[k] + <k, j> < Short[j],則令Short[j] Short[k] + <k, j>,同時Last[j] k。倘不存在任何一條弧滿足此條件則轉step 4。
step 3. 轉step 2.
step 4. 演算法結束。若Short[n + 1]= +∞,則不存在從S到T的路徑;否則可以根據Last記錄的有關信息得到最短路徑。
一次迭代演算法的時間復雜度為O(kn2),其中k是一個不大於n的變數。在費用流的求解過程中,k大部分情況下都遠小於n。
3.思維發散與探索
1)可改進路費用:「遞增!遞增?」
設f從零流到最大流共被改進了k次,每i次選擇的可改進路的費用為pi,那麼會不會有p1≤p2≤p3≤……≤pk呢?
2)迭代法:「小心死循環!嘿嘿……」
迭代法會出現死循環嗎?也就是說,構造的帶權有向圖B中會存在負迴路嗎?
3)費用:「你在乎我是負數嗎?」
網路流圖中的費用可以小於零嗎?
4)容量:「我管的可不僅是弧。」
網路流圖中的「容量」都是對弧而言的,但若是給每個頂點也加上一個容量限制:即通過此頂點的流量的上限;任務仍然是求從S到T的最小費用最大流。你能解決嗎?
四、有上下界的最大流
上面討論的網路流都只對每條弧都限定了上界(其實其下界可以看成0),現在給每條弧<Vi, Vj>加上一個下界限制Aij(即必須滿足Aij≤fij)。
例如圖5-9:
弧上數字對第一個是上界,第二個是下界。若是撇開下界不看,此圖的最大流如圖5-10(a)所示,流量是6;但若是加入了下界的限制,它的最大流量就只有5了,具體方案見圖5-10(b)。
那麼有上下界的網路最大流怎麼求呢?
一種自然的想法是去掉下界,將其轉化為只含上界的網路流圖。這種美好的願望是可以實現的。具體方法如下:
設原網路流圖為G = (V, E, C, A),構造不含下界的網路流圖G』 = (V』, E』, C』):
1、 V』 = V∪{S』, T』}
2、 對每個頂點x,令 ,若h-(x)≠0,就添加一條弧<S』, x>,其上界為h-(x)。
3、 對每個頂點x,令 ,若h+(x)≠0,就添加一條弧<x, T』>,其上界為h+(x)。
4、 對於任何<Vi, Vj>∈E,都有<Vi, Vj>∈E』,其上界C』ij = Cij – Aij。
5、 新增<T, S>∈E』,其上界CTS = +∞。
在G』中以S』為源點、T』為匯點求得最大流f』。若f』中從S』發出的任意一條弧是非飽和弧,則原網路流圖沒有可行流。否則可得原圖的一個可行流f = f』 + A,即所有的fij = f』ij + Aij。(其正確性很容易證明,留給讀者完成)
然後再求可改進路(反向弧<Vi, Vj>必須滿足fij≥Aij,而非fij≥0),不斷放大f,直到求出最大流。
我們看到,上幾節所討論的一種可行網路流實際上是{Aij = 0}的一種特殊網路流,這里提出的模型更一般化了。解決一般化的復雜問題,我們採取的思路是將其轉化為特殊的簡單問題,加以研究、推廣,進而解決。這是一種重要的基本思想:化歸——簡單有效。基於這種思想,請讀者自行思考解決:
1、 有上下界的最小流。
2、 有上下界的最小費用最大流。
五、多源點、多匯點的最大流
已知網路流圖有n個源點S1、S2、……、Sn,m個匯點T1、T2、……、Tm,,求該圖的最大流。這樣的問題稱為多源點、多匯點最大流。
它的解決很簡單:
1、 增設一個「超級源」S』,對每個源點Si,新增弧<S』, Si>,容量為無窮大。
2、 增設一個「超級匯」T』,對每個匯點Ti,新增弧<Ti, T』>,容量為無窮大。
3、 以S』為源點、T』為匯點求最大流f。
4、 將f中的S』和T』去掉,即為原圖的最大流。
演算法正確性顯然。
六、頂點有容量限制的最大流
上一節已經提出了這個問題,即對於進出每個頂點的流量也規定一個上限,這樣的最大流如何求?
既然我們已經解決了「邊限制」問題,現在何不把「點限制」問題轉化為「邊限制」呢?具體辦法如下:
1、 對除源點和匯點之外的每個頂點i拆分成兩個頂點i』和i』』。新增一條弧<i』, i』』>,其容量為點i的流量限制。
2、 對於原圖中的弧<i, j>,我們將其變換成<i』』, j』>。
3、 對變換後的圖求最大流即可。
這里我們又一次運用到了化歸的思想:將未知的「點限制」問題轉化為已知的「邊限制」問題。
七、網路流與二部圖的匹配
{二部圖和匹配的定義可參見本書專門介紹二部圖匹配的章節}
設二部圖為G = (X, Y, E)。
增設點S』,對於所有i∈X,新增弧<S』, Xi>,容量為1;增設點T』,對於所有i∈Y,新增一條弧<Yi, T』>,容量也為1。原圖中所有的弧予以保留,容量均為+∞。對新構造出來的網路流圖以S』為源點、T』為匯點求最大流:流量即為最大匹配數;若弧<Xi, Yj>(i∈X,j∈Y)的流量非零,它就是一條匹配邊。
二部圖最大匹配問題解決。
那麼二部圖的最佳匹配問題又如何?
仍然按照上述方法構圖。同時令原圖中弧的費用保持不變;新增弧的費用置為0。然後以S』為源點、T』為匯點求最小費用最大流即可。最大流的費用即為原二部圖最佳匹配的費用。
復制的我快吐了~
㈥ 誰懂網路流演算法
1.Fort_Fulkerson演算法. 2.Edmonds_Karp演算法. 3.Push_Relabel 演算法 4.Relabel_to_Front演算法.
<<演算法藝術與信息學競賽>>上介紹了五種演算法.
1.Fort_Fulkerson演算法. 2.最短增廣路演算法. 3.使用距離標號的最短增廣路演算法. 4.預流推進演算法 5.最高標號的預流推進演算法.
<<實用演算法分析與程序設計>>上介紹了一種演算法:
1.Dinic演算法.
另外在網上又看見一些其它演算法:
1.SAP演算法. 2.pre_flow 演算法 3.FIFO pre_flow演算法 。。。 。。。
其實不少演算法說的都是同一個東西,只是名稱不一樣,現在總結如下:
1.Fort_Fulkerson演算法.
2.Edmonds_Karp演算法(最短增廣路演算法).-------------------O( n*m^2 )
3.SAP演算法(使用距離標號的最短增廣路演算法).--------------O( n^2*m )
4.Dinic演算法.------------------------------------------------------O( n^2*m )
5.Push_Relabel演算法(預流推進演算法).------------------------O( n^2*m )
6.FIFO Preflow_Push演算法.------------------------------------O( n^2*m)
7.Relabel_to_Front演算法.---------------------------------------O( n^3 )
8.Highest Label Preflow_push演算法.--------------------------O( n^2*m^1/2)
㈦ 求下圖中vs到vt的最大流和最小截圖旁邊的數字是c
如下:
至於截集,定義為:給定網路D=(V,A,C),若點集V被分割成兩個非空集合V1和V2,使得V=V1+V2,V1∩
V2=φ(空集),且vs∈V1,vt∈V2,則把始點在V1,終點在V2的弧的集合稱為分離vs和vt的一個截集
然後,網路流演算法最重要的增廣鏈,正式定義為:
設 f = {Fij}是網路D=(V,A,C)上的一個可行流,u 是從 Vs到 Vt的一條鏈,若u 滿足下列條件:
(1)在弧 (vi,vj)∈μ+上,即 u+中的每一條弧都是非飽和弧;
(2)在弧 (vi,vj)∈μ-上,即u- 中的每一條弧都是非零流弧。則稱 是關於 的一條增廣鏈。
㈧ 如何向親戚朋友,解釋自己是搞演算法的
有些人覺得演算法競賽很有內容,比工程甚至普通的研究還有難度。我覺得這個是比較方法不太合適,寫個小爬蟲、做個個人網站、弄個C--編譯器,這種入門的東西當然簡單,但是我們搞競賽的時候入門的是什麼?A+B?高精度加減法?一樣水的很。你不能拿一個領域高級的東西去和另外一個領域入門的東西比。搞競賽搞得極致的巨巨當然很厲害,但他們身上不是只有競賽選手這么一個標簽,他們的成就也不是只靠搞競賽就搞出來的。況且,就像碼農群體大多是每天死於業務邏輯的搬磚工,科研群體很多時候都是浪費咖啡的灌水機一樣,競賽選手這個群體,更多的人是那些做不出來題的,讓大家拿金牌銀牌的那個基數(不要看不起基數,要是有一天這些基數決定不參加競賽了,大家一起玩完)。如果說搬磚灌水還填補了一些巨巨大牛沒有時間去做的東西,萬一銅鐵牌回家,除了鍛煉了自己的能力,我們敢說我們創造了什麼東西嗎?不能說麗潔姐姐搞過競賽,你也搞過競賽,你就搞過麗……(不對劃掉)你就也是麗潔姐姐這個水平了。我們是競賽選手,是演算法愛好者,在演算法上有了入門的機會,不去想著有朝一日去建模沒有人解決好的問題,也不想著將來如何去處理許多人想也不敢想的復雜或是大量的數據,過早的給自己固化一個標簽,滿足於這種答題的模式,我真的是覺得非常可惜。
利益相關:一個內心深處其實還是隱約的想搞演算法,但是清楚自己不是那塊料,省隊都進不去,算上邀請賽才敢說自己金銀銅鐵都拿過的退役OI/ICPCer
㈨ 網路流之最大流,您只需判斷這個代碼是屬於哪一種最大流演算法即可。
Edmonds - Karp 演算法
最簡單的增廣路類演算法,每次用一個 BFS 尋找最短增廣路
while(1) 里前半部分的 for 循環就是 BFS 部分,隊列 que[] 輔助進行 BFS,找到的增廣路存在 pre[i] 中
if(!pre[sink])判斷是否存在可到達匯點的增廣路,不存在就跳出循環
後半部分 for 循環對找到的路徑進行增廣操作。
時間復雜度 O(VE^2),行數雖少,但效率不是很高的演算法
最後說一句,這代碼風格太差了 = =,只考慮代碼長度完全不顧可讀性
參考資料是自己的 blog 呵呵
㈩ 薩普的SAP演算法
最短增廣路演算法(Shortest Augmenting Path Algorithm),是網路流中求最大流的經典演算法之一,即每次尋找包含弧的個數最少的增廣路進行增廣,可以證明,此演算法最多隻需要進行mn/2次增廣。並且引入距離標號的概念,可以在O(n)的時間里找到一條最短增廣路。最終的時間復雜度為O(n^2m),但在實踐中,時間復雜度遠遠小於理論值(特別是加了優化之後),因此還是很實用的。 對於每個頂點i賦予一個非負整數值d(i)來描述i到t的「距離」遠近,稱它為距離標號,並且滿足以下兩個條件: 1. d(t)=0 2. 對於殘留網路Gf中的一條弧(i,j),d(i)≤d(j)+1。
允許弧和允許路:
如果殘留網路Gf中的一條弧(i,j)滿足d(i)=d(j)+1,我們稱(i,j)是允許弧,由允許弧組成的一條s-t路徑是允許路。顯然,允許路是殘留網路Gf中的一條最短增廣路。當找不到允許路的時候,我們需要修改某些點的d(i)。 可以注意到一個事實:如果說在某次迭代中從i出發的弧(i,j)不是允許弧,則在頂點i的標號修改之前(i,j)都不可能是允許弧。(因為d(i)不變,d(j)不減且d(i)<d(j)+1)這樣,在查找允許弧的時候只需要從上一次找到的允許弧開始找。所以我們增加「當前弧」這個數據結構,記錄當前頂點找到的允許弧,只有在修改這個頂點標號時才會更改這個頂點的當前弧。
最後附上我寫的部分程序,用的非遞歸結構
Fillchar(last, Sizeof(last), $ff); Fillchar(first, Sizeof(first), $ff);
Procere add(x, y, z, k: Longint);
Begin
Inc(num);
e[num].x := x;
e[num].y := y;
e[num].z := z;
e[num].next := k;
If first[x]=-1 Then first[x] := num;
If last[x]=-1 Then last[x] := num Else Begin
e[last[x]].next := num;
last[x] := num;
End;
End;
這個加邊,用數組模擬鏈表的鄰接表
now := First;
i := 1;
c := maxlongint;
vh[0] := n;
While dis[1]<n Do Begin(dis存距離標號)
fc[i] := c;(fc用於遞歸c的值)
ff := False;(表示是否找到允許弧)
k := now[i];(now存當前弧)
While k<>-1 Do Begin
j := e[k].y;
If (e[k].z>0) And (dis[j]+1=dis[i]) Then Begin
ff := True;
now[i] := k;
If e[k].z<c Then c := e[k].z;
pre[j] := k;
i := j;
If i=n Then Begin(找到增廣路)
Inc(ans, c);
While i<>1 Do Begin
dec(e[pre[i]].z, c);
Inc(e[pre[i] xor 1].z, c);
i := e[pre[i]].x;
End;
c := Maxlongint;
End;
Break;
End;
k := e[k].next;
End;
If ff Then Continue;
min := n-1;(重新標號)
k := First[i];
While (k<>-1) Do Begin
j := e[k].y;
If (e[k].z>0) And (dis[j]<min) then Begin
tj := k;
min := dis[j];
End;
k := e[k].next;
End;
now[i] := tj;
dec(vh[dis[i]]);(gap)
If vh[dis[i]]=0 Then Break;
dis[i] := min+1;
Inc(vh[dis[i]]);
If i<>1 Then Begin
i := e[pre[i]].x;
c := fc[i];
End;
End;