Power Network POJ - 1459(EK算法模板+详解)
題意:
總共有a個節點,其中有發電站b個、用戶c個和調度器a-b-c個三種節點,每個發電站有一個最大發電量,每個用戶有個最大接受電量,現在有d條有向邊,邊有一個最大的流量代表,最多可以流出這么多電,現在從發電站發電到用戶,
問最多可以發多少電。
題目:
A power network consists of nodes (power stations, consumers and dispatchers) connected by power transport lines. A node u may be supplied with an amount s(u) >= 0 of power, may produce an amount 0 <= p(u) <= p max(u) of power, may consume an amount 0 <= c(u) <= min(s(u),c max(u)) of power, and may deliver an amount d(u)=s(u)+p(u)-c(u) of power. The following restrictions apply: c(u)=0 for any power station, p(u)=0 for any consumer, and p(u)=c(u)=0 for any dispatcher. There is at most one power transport line (u,v) from a node u to a node v in the net; it transports an amount 0 <= l(u,v) <= l max(u,v) of power delivered by u to v. Let Con=Σ uc(u) be the power consumed in the net. The problem is to compute the maximum value of Con.
An example is in figure 1. The label x/y of power station u shows that p(u)=x and p max(u)=y. The label x/y of consumer u shows that c(u)=x and c max(u)=y. The label x/y of power transport line (u,v) shows that l(u,v)=x and l max(u,v)=y. The power consumed is Con=6. Notice that there are other possible states of the network but the value of Con cannot exceed 6.
Input
There are several data sets in the input. Each data set encodes a power network. It starts with four integers: 0 <= n <= 100 (nodes), 0 <= np <= n (power stations), 0 <= nc <= n (consumers), and 0 <= m <= n^2 (power transport lines). Follow m data triplets (u,v)z, where u and v are node identifiers (starting from 0) and 0 <= z <= 1000 is the value of l max(u,v). Follow np doublets (u)z, where u is the identifier of a power station and 0 <= z <= 10000 is the value of p max(u). The data set ends with nc doublets (u)z, where u is the identifier of a consumer and 0 <= z <= 10000 is the value of c max(u). All input numbers are integers. Except the (u,v)z triplets and the (u)z doublets, which do not contain white spaces, white spaces can occur freely in input. Input data terminate with an end of file and are correct.
Output
For each data set from the input, the program prints on the standard output the maximum amount of power that can be consumed in the corresponding network. Each result has an integral value and is printed from the beginning of a separate line.
Sample Input
2 1 1 2 (0,1)20 (1,0)10 (0)15 (1)20
7 2 3 13 (0,0)1 (0,1)2 (0,2)5 (1,0)1 (1,2)8 (2,3)1 (2,4)7
(3,5)2 (3,6)5 (4,2)7 (4,3)5 (4,5)1 (6,0)5
(0)5 (1)2 (3)2 (4)1 (5)4
Sample Output
15
6
Hint
The sample input contains two data sets. The first data set encodes a network with 2 nodes, power station 0 with pmax(0)=15 and consumer 1 with cmax(1)=20, and 2 power transport lines with lmax(0,1)=20 and lmax(1,0)=10. The maximum value of Con is 15. The second data set encodes the network from figure 1.
分析:
因為是多源點多匯點,所以我們要設置一個總源點和總匯點,使得總源點0到其他各源點,其他各匯點到總匯點a+1,然后就是普通的最大流問題
#include<stdio.h> #include<string.h> #include<queue> #include<algorithm> using namespace std; const int inf=0x3f3f3f3f; const int M=110;int a/**節點*/,b/**發電站*/,c/**用戶*/,d/**有向邊輸電路*/; int dp[M][M]/**從u到v的容量*/,f[M][M]/**流量*/,e[M],pre[M]; /*通??梢园堰@些邊想象成道路,流量就是這條道路的車流量, 容量就是道路可承受的最大的車流量。很顯然的,流量<=容量。 而對于每個不是源點和匯點的點來說,可以類比的想象成沒有存儲功能的貨物的中轉站, 所有”進入”他們的流量和等于所有從他本身”出去”的流量。*/ int EK(int s,int t)//最基礎的最大流求法,即bfs找增廣路法 {int ans=0;queue<int>q;//把queue<int>q寫在while(true)外面比寫在里面快了500mswhile(1)///不斷地從起點開始尋找增廣路,每次都對其進行增廣{memset(e,0,sizeof(e));e[s]=inf;q.push(s); /**找尋這么一條路,這條路從源點開始一直一段一段的連到了匯點, 并且,這條路上的每一段都滿足流量f<容量dp,注意,是嚴格的<,而不是<=。*/while(!q.empty()){int u=q.front();q.pop();for(int v=0;v<=a+1;v++){if(!e[v]&&dp[u][v]>f[u][v]){e[v]=min(e[u],dp[u][v]-f[u][v]);/**找到這條路上的每一段的(容量-流量)的值當中的最小值delta。*/pre[v]=u;q.push(v);}}}if(!e[t])/***直到源點和匯點不連通, 也就是找不到增廣路為止。當前的流量就是最大流*/ break;for(int u=t;u!=s;u=pre[u]){f[pre[u]][u]+=e[t];/**我們把這條路上每一段的流量 都加上這個delta,一定可以保證這個流依然是可行流,這是顯然的。*/f[u][pre[u]]-=e[t];/**給程序一個”后悔”的機會,回溯搜索效率就上升到指數級了。 算法神奇的利用了一個叫做反向邊的概念來解決這個問題。即每條邊(I,j)都有一條反向邊(j,i),反向邊也同樣有它的容量。*/}ans+=e[t];/**得到了一個更大的流, 他的流量是之前的流量+delta,而這條路就叫做增廣路*/}return ans; } int main() {while(~scanf("%d%d%d%d",&a,&b,&c,&d)){memset(dp,0,sizeof(dp));memset(f,0,sizeof(f));for(int i=0;i<d;i++)///d條輸電路{int u,v,w;scanf(" (%d,%d)%d",&u,&v,&w);// scanf("(%d,%d)%d",&u,&v,&w);dp[u+1][v+1]+=w;}for(int i=0;i<b;i++)///增加一個超級源點,所給的發電站都和超級源點相連{int v,w;scanf(" (%d)%d",&v,&w);// scanf("%d%d",&v,&w);dp[0][v+1]+=w;}for(int i=0;i<c;i++)///增加一個超級匯點,所給的用戶都和超級匯點相連{int u,w;scanf(" (%d)%d",&u,&w);//scanf("%d%d",&u,&w);dp[u+1][a+1]+=w;}printf("%d\n",EK(0,a+1));}return 0; }KM算法詳解(轉)
一、概念引入
首先要先清楚最大流的含義,就是說從源點到經過的所有路徑的最終到達匯點的所有流量和。
流網絡G=(V,E)是一個有向圖,其中每條邊(u,v)∈E均有一個非負容量c(u,v)>=0。如果(u,v)不屬于E,則假定c(u,v)=0。流網絡中有兩個特別的頂點:源點s和匯點t。下圖展示了一個流網絡的實例(其中斜線左邊的數字表示實際邊上的流,右邊的數字表示邊的最大容量):
二、基礎知識準備
對一個流網絡G=(V,E),其容量函數為c,源點和匯點分別為s和t。G的流f滿足下列三個性質:
容量限制:對所有的u,v∈V,要求f(u,v)<=c(u,v)。
反對稱性:對所有的u,v∈V,要求f(u,v)=-f(v,u)。
流守恒性:對所有u∈V-{s,t},要求∑f(u,v)=0 (v∈V)。
容量限制說明了從一個頂點到另一個頂點的網絡流不能超過設定的容量,就好像是一個管道只能傳輸一定容量的水,而不可能超過管道體積的限制;反對稱性說明了從頂點u到頂點v的流是其反向流求負所得,就好像是當參考方向固定后,站在不同的方向看,速度一正一負;而流守恒性說明了從非源點或非匯點的頂點出發的點網絡流之和為0,這有點類似于基爾霍夫電流定律,且不管什么是基爾霍夫電流定律,通俗的講就是進入一個頂點的流量等于從該頂點出去的流量,如果這個等式不成立,必定會在該頂點出現聚集或是枯竭的情況,而這種情況是不應該出現流網絡中的,所以一般的最大流問題就是在不違背上述原則的基礎上求出從源點s到匯點t的最大的流量值,顯然這個流量值應該定義為從源點出發的總流量或是最后聚集到t的總流量,即流f的值定義為|f|=∑f(s,v) (v∈V)。
在求解最大流的問題前,必須對三個概念有所了解:殘留網絡,增廣路徑和割。下面先給出這三個概念的基本內容。
a.在給定的流網絡G=(V,E)中,設f為G中的一個流,并考察一對頂點u,v∈V,在不超過容量c(u,v)的條件下,從u到v之間可以壓入的額外網絡流量,就是(u,v)的殘留容量,就好像某一個管道的水還沒有超過管道的上限,那么就這條管道而言,就一定還可以注入更多的水。殘留容量的定義為:cf(u,v)=c(u,v)-f(u,v)。而由所有屬于G的邊的殘留容量所構成的帶權有向圖就是G的殘留網絡。下圖就是上面的流網絡所對應的殘留網絡:
殘留網絡中的邊既可以是E中邊,也可以是它們的反向邊。只有當兩條邊(u,v)和(v,u)中,至少有一條邊出現在初始網絡中時,邊(u,v)才會出現在殘留網絡中。下面是一個有關殘留網絡的定理,若f是G中的一個流,Gf是由G導出的殘留網絡,f’是Gf中的一個流,則f+f’是G中一個流,且其值|f+f’|=|f|+|f’|。證明時只要證明f+f’這個流在G中滿足之前所講述的三個原則即可。在這里只給出理解性的證明,可以想象如果在一個管道中流動的水的總流量為f,而在該管道剩余的流量中存在一個流f’可以滿足不會超過管道剩余流量的最大限,那么將f和f’合并后,也必定不會超過管道的總流量,而合并后的總流量值也一定是|f|+|f’|。
b.增廣路徑p為殘留網絡Gf中從s到t的一條簡單路徑。根據殘留網絡的定義,在不違反容量限制的條件下,G中所對應的增廣路徑上的每條邊(u,v)可以容納從u到v的某額外正網絡流。而能夠在這條路徑上的網絡流的最大值一定是p中邊的殘留容量的最小值。這還是比較好理解的,因為如果p上的流大于某條邊上的殘留容量,必定會在這條邊上出現流聚集的情況。所以我們將最大量為p的殘留網絡定義為:cf§=min{cf(u,v) | (u,v)在p上}。而結合之前在殘留網絡中定理,由于p一定是殘留網絡中從s到t的一條路徑,且|f’|=cf§,所以若已知G中的流f,則有|f|+|cf§|>|f|且|f|+|cf§|不會超過容量限制。
c.流網絡G(V,E)的割(S,T)將V劃分成為S和T=V-S兩部分,使得s∈S,t∈T。如果f是一個流,則穿過割(S,T)的凈流被定義為f(S,T)=∑f(x,y) (x∈S,y∈T),割(S,T)的容量為c(S,T)。一個網絡的最小割就是網絡中所有割中具有最小容量的割。設f為G中的一個流,且(S,T)是G中的一個割,則通過割(S,T)的凈流f(S,T)=|f|。因為f(S,T)=f(S,V)-f(S,S)=f(S,V)=f(s,V)+f(S-s,V)=f(s,V)=|f|(這里的公式根據f(X,Y)=∑f(x,y) (x∈X,y∈Y)的定義,以及前面的三個限制應該還是可以推出來的,這里就不細講了)。有了上面這個定理,我們可以知道當把流不斷增大時,流f的值|f|不斷的接近最小割的容量直到相等,如果這時可以再增大流f,則f必定會超過某個最小的割得容量,則就會存在一個f(S,T)<=c(S,T)<|f|,顯然根據上面的定理這是不可能。所以最大流必定不超過網絡最小割的容量。
綜合上面所講,有一個很重要的定理:最大流最小割定理
如果f是具有源s和匯點t的流網絡G=(V,E)中的一個流,則下列條件是等價的:
1) f是G中一個最大流。
2) 殘留網絡Gf不包含增廣路徑。
3) 對G的某個割(S,T),有|f|=c(S,T)。
總結
以上是生活随笔為你收集整理的Power Network POJ - 1459(EK算法模板+详解)的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 凸包算法知识总结
- 下一篇: 绿豆饼的功效与作用、禁忌和食用方法