日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當(dāng)前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

[Poj 1459] 网络流(一) {基本概念与算法}

發(fā)布時(shí)間:2025/1/21 编程问答 14 豆豆
生活随笔 收集整理的這篇文章主要介紹了 [Poj 1459] 网络流(一) {基本概念与算法} 小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.

{

凸包的內(nèi)容還欠整理

先來侃侃一個(gè)月以前就想寫寫的網(wǎng)絡(luò)流

本文介紹網(wǎng)絡(luò)流 網(wǎng)絡(luò)流的算法 及其應(yīng)用

這些問題沒事想想還是很有意思的

}

==================================================================================

一.網(wǎng)絡(luò)流:流&網(wǎng)絡(luò)&

1.網(wǎng)絡(luò)流問題(NetWork Flow Problem):

給定指定的一個(gè)有向圖,其中有兩個(gè)特殊的點(diǎn)源S(Sources)和匯T(Sinks),每條邊有指定的容量(Capacity),求滿足條件的從S到T的最大流(MaxFlow).

The network flow problem considers a graph G with a set of sources S and sinks T and for which each edge has an assigned capacity (weight), and then asks to find the maximum flow that can be routed from S to T while respecting the given edge capacities.

http://mathworld.wolfram.com/NetworkFlow.html

下面給出一個(gè)通俗點(diǎn)的解釋

(下文基本避開形式化的證明 基本都用此類描述敘述)

好比你家是匯 自來水廠(有需要的同學(xué)可以把自來水廠當(dāng)成銀行之類 以下類似)是源

然后自來水廠和你家之間修了很多條水管子接在一起 水管子規(guī)格不一 有的容量大 有的容量小

然后問自來水廠開閘放水 你家收到水的最大流量是多少

如果自來水廠停水了 你家那的流量就是0 當(dāng)然不是最大的流量

但是你給自來水廠交了100w美金 自來水廠拼命水管里通水 但是你家的流量也就那么多不變了 這時(shí)就達(dá)到了最大流

-------------------------------------------------------------------------------------------------------------

2.三個(gè)基本的性質(zhì):

如果 C代表每條邊的容量 F代表每條邊的流量

一個(gè)顯然的實(shí)事是F小于等于C 不然水管子就爆了

這就是網(wǎng)絡(luò)流的第一條性質(zhì) 容量限制(Capacity Constraints):F<x,y> ≤ C<x,y>

再考慮節(jié)點(diǎn)任意一個(gè)節(jié)點(diǎn) 流入量總是等于流出的量 否則就會(huì)蓄水(爆炸危險(xiǎn)...)或者平白無故多出水(有地下水涌出?)

這是第二條性質(zhì) 流量守恒(Flow Conservation):Σ F<v,x> = Σ F<x,u>

當(dāng)然源和匯不用滿足流量守恒 我們不用去關(guān)心自來水廠的水是河里的 還是江里的

(插播廣告: 節(jié)約水資源 人人有責(zé)!)

最后一個(gè)不是很顯然的性質(zhì) 是斜對(duì)稱性(Skew Symmetry): F<x,y> = - F<y,x>

這其實(shí)是完善的網(wǎng)絡(luò)流理論不可缺少的 就好比中學(xué)物理里用正負(fù)數(shù)來定義一維的位移一樣

百米起點(diǎn)到百米終點(diǎn)的位移是100m的話 那么終點(diǎn)到起點(diǎn)的位移就是-100m

同樣的 x向y流了F的流 y就向x流了-F的流

-------------------------------------------------------------------------------------------------------------

3.容量網(wǎng)絡(luò)&流量網(wǎng)絡(luò)&殘留網(wǎng)絡(luò):

網(wǎng)絡(luò)就是有源匯的有向圖 關(guān)于什么就是指邊權(quán)的含義是什么

容量網(wǎng)絡(luò)就是關(guān)于容量的網(wǎng)絡(luò) 基本是不改變的(極少數(shù)問題需要變動(dòng))

流量網(wǎng)絡(luò)就是關(guān)于流量的網(wǎng)絡(luò) 在求解問題的過程中

通常在不斷的改變 但是總是滿足上述個(gè)性質(zhì)

調(diào)整到最后就是最大流網(wǎng)絡(luò) 同時(shí)也可以得到最大流值

殘留網(wǎng)絡(luò)往往概括了容量網(wǎng)絡(luò)和流量網(wǎng)絡(luò) 是最為常用的

殘留網(wǎng)絡(luò)=容量網(wǎng)絡(luò)-流量網(wǎng)絡(luò)

這個(gè)等式是始終成立的 殘留值當(dāng)流量值為負(fù)時(shí)甚至?xí)笥谌萘恐?/p>

流量值為什么會(huì)為負(fù)?有正必有負(fù),記住斜對(duì)稱性!

-------------------------------------------------------------------------------------------------------------

4.割&割集:

無向圖的割集(Cut Set):C[A,B]是將圖G分為A和B兩個(gè)點(diǎn)集 A和B之間的邊的全集

A set of edges of a graph which, if removed (or "cut"), disconnects the graph (i.e., forms a disconnected graph).

http://mathworld.wolfram.com/CutSet.html

網(wǎng)絡(luò)的割集:C[S,T]是將網(wǎng)絡(luò)G分為s和t兩部分點(diǎn)集 S屬于s且T屬于t 從S到T的邊的全集

帶權(quán)圖的割(Cut)就是割集中邊或者有向邊的權(quán)和

Given a weighted, undirected graph G=(V,E) and a graphical partition of V into two sets A and B, the cut of G with respect to A and B is defined as cut(A,B)=sum_(i in A,j in B)W(i,j),where W(i,j) denotes the weight for the edge connecting vertices i and j. The weight of the cut is the sum of weights of edges crossing the cut.

http://mathworld.wolfram.com/Cut.html

通俗的理解一下:

割集好比是一個(gè)恐怖分子 把你家和自來水廠之間的水管網(wǎng)絡(luò)砍斷了一些

然后自來水廠無論怎么放水 水都只能從水管斷口嘩嘩流走了 你家就停水了

(插播廣告: 節(jié)約水資源 人人有責(zé)!)

割的大小應(yīng)該是恐怖分子應(yīng)該關(guān)心的事 畢竟細(xì)管子好割一些

而最小割花的力氣最小

==================================================================================

二.計(jì)算最大流的基本算法

那么怎么求出一個(gè)網(wǎng)絡(luò)的最大流呢?

這里介紹一個(gè)最簡(jiǎn)單的算法:Edmonds-Karp算法最短路徑增廣算法 簡(jiǎn)稱EK算法

EK算法基于一個(gè)基本的方法:Ford-Fulkerson方法增廣路方法 簡(jiǎn)稱FF方法

增廣路方法是很多網(wǎng)絡(luò)流算法的基礎(chǔ) 一般都在殘留網(wǎng)絡(luò)中實(shí)現(xiàn)

其思路是每次找出一條從源到匯的能夠增加流的路徑 調(diào)整流值和殘留網(wǎng)絡(luò) 不斷調(diào)整直到?jīng)]有增廣路為止

FF方法的基礎(chǔ)是增廣路定理(Augmenting Path Theorem):網(wǎng)絡(luò)達(dá)到最大流當(dāng)且僅當(dāng)殘留網(wǎng)絡(luò)中沒有增廣路

證明略 這個(gè)定理應(yīng)該能夠接受的吧

EK算法就是不斷的找最短路 找的方法就是每次找一條邊數(shù)最少的增廣 也就是最短路徑增廣

這樣就產(chǎn)生了三個(gè)問題:

-------------------------------------------------------------------------------------------------------------

1.最多要增廣多少次?

可以證明 最多O(VE)次增廣 可以達(dá)到最大流 證明略

2.如何找到一條增廣路?

先明確什么是增廣路 增廣路是這樣一條從s到t的路徑 路徑上每條邊殘留容量都為正

把殘留容量為正的邊設(shè)為可行的邊 那么我們就可以用簡(jiǎn)單的BFS得到邊數(shù)最少的增廣路

3.如何增廣?

BFS得到增廣路之后 這條增廣路能夠增廣的流值 是路徑上最小殘留容量邊決定的

把這個(gè)最小殘留容量MinCap值加到最大流值Flow上 同時(shí)路徑上每條邊的殘留容量值減去MinCap

最后 路徑上每條邊的反向邊殘留容量值要加上MinCap 為什么? 下面會(huì)具體解釋

-------------------------------------------------------------------------------------------------------------

這樣每次增廣的復(fù)雜度為O(E) EK算法的總復(fù)雜度就是O(VE^2)

事實(shí)上 大多數(shù)網(wǎng)絡(luò)的增廣次數(shù)很少 EK算法能處理絕大多數(shù)問題

平均意義下增廣路算法都是很快的

增廣路算法好比是自來水公司不斷的往水管網(wǎng)里一條一條的通水

上面還遺留了一個(gè)反向邊的問題: 為什么增廣路徑上每條邊的反向邊殘留容量值要加上MinCap?

因?yàn)?strong>斜對(duì)稱性! 由于殘留網(wǎng)絡(luò)=容量網(wǎng)絡(luò)-流量網(wǎng)絡(luò)

容量網(wǎng)絡(luò)不改變的情況下

由于增廣好比給增廣路上通了一條流 路徑說所有邊流量加MinCap

流量網(wǎng)絡(luò)中路徑上邊的流量加MinCap 反向邊流量減去MinCap

相對(duì)應(yīng)的殘留網(wǎng)絡(luò)就發(fā)生相反的改變

這樣我們就完成了EK算法 具體實(shí)現(xiàn)可以用鄰接表存圖 也可以用鄰接矩陣存圖

鄰接表存圖 由于流量同時(shí)存在于邊與反向邊 為了方便求取反向邊 建圖把一對(duì)互為反向邊的邊建在一起

代碼很簡(jiǎn)單 最好自己實(shí)現(xiàn)一下

EK const maxn=1000;
oo
=maxlongint;
var a,b,c,n,m,h,t,i,min,ans:longint;
g:
array[1..maxn,1..maxn]of longint;
q,p,prev:
array[1..maxn]of longint;
flag:boolean;
begin
assign(input,
'Ditch.in'); reset(input);
assign(output,
'Ditch.out'); rewrite(output);
while not eof do
begin
readln(m,n);
fillchar(g,sizeof(g),
0);
for i:=1 to m do
begin
readln(a,b,c);
g[a,b]:
=g[a,b]+c;
end;
ans:
=0;
while true do
begin
h:
=1; t:=1;
fillchar(p,sizeof(p),
0);
q[
1]:=1; p[1]:=1;
flag:
=false;
while h<=t do
begin
for i:=1 to n do
if (p[i]=0)and(g[q[h],i]>0)
then begin
inc(t); q[t]:
=i;
p[i]:
=1; prev[t]:=h;
if q[t]=n
then begin
flag:
=true;
break;
end;
end;
if flag then break;
inc(h);
end;
if not flag
then break;
i:
=t; min:=oo;
while q[i]<>1 do
begin
if g[q[prev[i]],q[i]]<min
then min:=g[q[prev[i]],q[i]];
i:
=prev[i];
end;
i:
=t;
while q[i]<>1 do
begin
g[q[prev[i]],q[i]]:
=g[q[prev[i]],q[i]]-min;
g[q[i],q[prev[i]]]:
=g[q[i],q[prev[i]]]+min;
i:
=prev[i];
end;
ans:
=ans+min;
end;
writeln(ans);
end;
close(input); close(output);
end.

看一個(gè)具體的增廣路算法的例子吧

==================================================================================

三.最大流最小割定理

下面介紹網(wǎng)絡(luò)流理論中一個(gè)最為重要的定理

最大流最小割定理(Maximum Flow, Minimum Cut Theorem):網(wǎng)絡(luò)的最大流等于最小割

The maximum flow between vertices v_i and v_j in a graph G is exactly the weight of the smallest set of edges to disconnect G with v_i and v_j in different components.

http://mathworld.wolfram.com/MaximumFlowMinimumCutTheorem.html

具體的證明分三部分

1.任意一個(gè)流都小于等于任意一個(gè)割

這個(gè)很好理解 自來水公司隨便給你家通點(diǎn)水 構(gòu)成一個(gè)流

恐怖分子隨便砍幾刀 砍出一個(gè)割

由于容量限制 每一根的被砍的水管子流出的水流量都小于管子的容量

每一根被砍的水管的水本來都要到你家的 現(xiàn)在流到外面 加起來得到的流量還是等于原來的流

管子的容量加起來就是割 所以流小于等于割

由于上面的流和割都是任意構(gòu)造的 所以任意一個(gè)流小于任意一個(gè)割

2.構(gòu)造出一個(gè)流等于一個(gè)割

當(dāng)達(dá)到最大流時(shí) 根據(jù)增廣路定理

殘留網(wǎng)絡(luò)中s到t已經(jīng)沒有通路了 否則還能繼續(xù)增廣

我們把s能到的的點(diǎn)集設(shè)為S 不能到的點(diǎn)集為T

構(gòu)造出一個(gè)割集C[S,T] S到T的邊必然滿流 否則就能繼續(xù)增廣

這些滿流邊的流量和就是當(dāng)前的流即最大流

把這些滿流邊作為割 就構(gòu)造出了一個(gè)和最大流相等的割

3.最大流等于最小割

設(shè)相等的流和割分別為Fm和Cm

則因?yàn)槿我庖粋€(gè)流小于等于任意一個(gè)割

任意F≤Fm=Cm≤任意C

定理說明完成

==================================================================================

四.簡(jiǎn)單的應(yīng)用

Poj 1459是一個(gè)很典型的網(wǎng)絡(luò)流應(yīng)用

把電流想象成水流

http://poj.org/problem?id=1459

注意把多源多匯轉(zhuǎn)化為單源單匯即可利用EK算法解決問題

網(wǎng)絡(luò)流的應(yīng)用還有很多 化歸的思想是網(wǎng)絡(luò)流最具魅力的地方

代碼如下:

PowerNet 1 const maxh=10;
2 maxn=100; maxq=110;
3 num:set of char=['0'..'9'];
4 oo=1000000;
5 ?var c,f:array[0..maxn+1,0..maxn+1]of longint;
6 n,m,k1,k2,tx,hx,head,tail,s,t,x,y,z,i:longint;
7 pre,h:array[0..maxn+1]of longint;
8 p:array[0..maxn+1]of boolean;
9 q:array[1..maxq]of longint;
10 ?procedure getc(var x:longint);
11 ?var ch:char;
12 ?begin
13 x:=0;
14 read(ch);
15 while not(ch in num) do
16 read(ch);
17 while ch in num do
18 begin
19 x:=x*10+ord(ch)-48;
20 read(ch);
21 end;
22 end;
23 procedure pop;
24 begin
25 p[q[head]]:=false;
26 inc(head); inc(hx);
27 if head>maxq then head:=1;
28 end;
29 procedure push(x:longint);
30 begin
31 inc(tail); inc(tx);
32 if tail>maxq then tail:=1;
33 q[tail]:=x; p[x]:=true;
34 end;
35 function min(x,y:longint):longint;
36 begin
37 min:=x;
38 if y<x then min:=y;
39 end;
40 begin
41 assign(input,'PowerNet.in'); reset(input);
42 assign(output,'PowerNet.out'); rewrite(output);
43 while not seekeof do
44 begin
45 read(n,k1,k2,m);
46 s:=n; t:=n+1;
47 fillchar(c,sizeof(c),0);
48 for i:=1 to m do
49 begin
50 getc(x); getc(y); getc(z);
51 c[x,y]:=c[x,y]+z;
52 end;
53 for i:=1 to k1 do
54 begin
55 getc(x); getc(y);
56 c[s,x]:=y;
57 end;
58 for i:=1 to k2 do
59 begin
60 getc(x); getc(y);
61 c[x,t]:=y;
62 end;
63 hx:=1; tx:=0;
64 head:=1; tail:=0;
65 fillchar(p,sizeof(p),false);
66 p[s]:=true; p[t]:=true;
67 fillchar(f,sizeof(f),0);
68 fillchar(pre,sizeof(pre),0);
69 fillchar(h,sizeof(h),0);
70 h[s]:=maxh; dec(n);
71 for i:=0 to n do
72 if c[s,i]>0
73 then begin
74 h[i]:=1; pre[i]:=c[s,i];
75 f[s,i]:=c[s,i]; f[i,s]:=-c[s,i];
76 push(i);
77 end;
78 while hx<=tx do
79 begin
80 x:=q[head];
81 for i:=0 to t do
82 begin
83 y:=c[x,i]-f[x,i];
84 if (h[x]=h[i]+1)and(y>0)
85 then begin
86 if not p[i] then push(i);
87 z:=min(pre[x],y);
88 f[x,i]:=f[x,i]+z;
89 f[i,x]:=f[i,x]-z;
90 pre[x]:=pre[x]-z;
91 pre[i]:=pre[i]+z;
92 end;
93 if pre[x]=0 then break;
94 end;
95 pop;
96 if pre[x]>0
97 then begin
98 y:=oo;
99 for i:=0 to t do
100 if c[x,i]>f[x,i]
101 then y:=min(y,h[i]);
102 h[x]:=y+1;
103 push(x);
104 end;
105 end;
106 writeln(pre[t]);
107 end;
108 close(input); close(output);
109 end. ==================================================================================

本文部分圖片來源:

http://wenku.baidu.com/view/65a8290d4a7302768e99395a.html

http://wenku.baidu.com/view/6b4baf1ffc4ffe473368ab25.html

http://www.cppblog.com/mythit/archive/2009/04/19/80470.aspx

轉(zhuǎn)載于:https://www.cnblogs.com/Booble/archive/2011/03/04/1970453.html

總結(jié)

以上是生活随笔為你收集整理的[Poj 1459] 网络流(一) {基本概念与算法}的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網(wǎng)站內(nèi)容還不錯(cuò),歡迎將生活随笔推薦給好友。