網絡流(1)——網絡、流網絡和網絡流

  在現實世界中,咱們的生活受到大量網絡的支配。網絡流能夠表示不少模型,好比管道中的石油、高壓線中電流,或者計算機網絡中的數據。網絡流也能夠解決不少問題,好比如何進行道路交通管控,以便有效地緩解早高峯的擁堵;在物流網運輸中,在知足供需關係的同時,怎樣使渠道成本最低;在轟炸機執行轟炸任務時,怎樣才能給敵軍補給線形成更嚴重的打擊。這些問題都有現成的網絡流算法,別再覺得網絡流僅僅是網絡中的比特流。算法

網絡和流網絡

  簡單地說,流網絡是一種有加權邊的有向圖。在數學中,網絡是這樣定義的:網絡(Networks)G=(V,E,s,t,C) 是一個五元組。其中(V, E)是一個有向圖,V是頂點的集合,E是邊的集合,它們都是非負實數集;st是(V, E)中的兩個不一樣頂點;s的入度爲0(沒有指向s的邊),是G的源點(source);t的出度爲0(沒有邊從t發出),是G的匯點(sink);C是容量函數,對於(V, E)中的任意有向邊 a,稱 C(a)是邊 a 的容量(capacity)。對於僅有一個指定的原點s和指定的匯點t的網絡,稱爲st-網。網絡

  實際上網絡的概念至關直白,咱們以一個簡單的物理模型直觀地解釋網絡。假設有一組聯通的輸油管道,管道鏈接處的中轉站設有控制開關。這組管道的源頭是一個油田,匯點是一個煉油廠,石油從油田流出,最終匯入煉油廠:數據結構

圖1函數

  圖1是一個帶有加權邊的有向圖,也是一個典型的st-網。其中v1表明油田,是源點s,v6表明煉油廠,是匯點t,其它頂點表明中轉站;每條邊表明一個輸油管道,邊上的數字是管道的容量,數字越大,管道越粗,單位時間可以流過管道的油量也越大。把這些信息映射到網絡的定義,那麼:post

  輸油管道會按期保養,不會產生漏油的狀況,更不會無緣無故生出石油,所以全部邊的容量都是正值,這種全部容量都是正數的st-網稱爲流網絡(Flow Network)。對於流網絡來講,頂點沒有容量。做爲一個樞紐,中轉站並不存儲石油,只負責經過開關控制石油流動的方向;一樣,石油只是流過輸油管道,並不會在管道中積累或彙集。學習

流、網絡流和網絡流的值

  石油將在流網絡的管道中流動,這些流動的石油就是流網絡中的流。很顯然,管道中的石油不能超過管道的寬度。在流網絡模型上,流能夠看做另外一組隱藏的邊權值,稱爲邊流。流網絡有多條邊,固然也有多個流。對於輸油網的各個中轉站來講,因爲沒有存儲功能,所以流入的中轉站的石油等於流出中轉站的石油。spa

  這些特色歸能夠納出流的定義:一個網絡G=(V,E,s,t,C)是流網絡,它的一個流是一個函數f,這個函數知足2個條件:計算機網絡

  (1)容量限制,對於任意的邊 a, 0≤f(a)≤C(a),即邊的流不會大於該邊的容量。3d

  (2)守恆定律,對於任意內部頂點v ,進入頂點的流量等於從該頂點發出的流量,簡稱「流入等於流出」。code

  做爲流網絡的源頭,沒有流入原點的邊;相似地,也沒有從匯點流出的邊。假設石油從油田到煉油廠的傳輸過程當中沒有任何損失,那麼石油從源點的流出量等於匯點的流入量。

  爲了方便地展現網絡中的流,咱們先對網絡的表示加以改進,用邊的寬度表示邊的容量,使寬度和容量成正比,管道越寬,容量也越大:

圖2

  當石油流過輸油管道時,管道將被填充。咱們以實心箭頭表明石油,填充原來的管道,流的值和管道的容量成正比:

圖3

  在圖3中,邊v2v4的容量是1,流也是1,此時咱們說這條邊是滿邊,用星號表示滿邊的流值。邊v1v3的容量是3,流是1,說明這條管道並無獲得充分利用,實心箭頭填充了管道1/3的空間。邊v5v4的容量是1,流是0,v5v4處的開關是閉合的,這條管道處於閒置狀態。

  圖3也展現了從源點到匯點的全部流,所以咱們也稱圖3是一個網絡流(network-flows)。

  流網絡、流、網絡流,看起來極爲類似,不少資料中也互相混用,但三者仍是有所區別。網絡流是指全部容量都是正數的st-網;流表明個體,特指某一條邊上的流量;網絡流表明總體,表示流網絡上全部流的集合。此外,網絡流還有另外一個含義,指用流網絡的模型找出解決問題的方法。網絡流的含義到底是集合仍是方法,須要根據具體的上下文而定。一般來說,這些概念在實際問題中很是直白,沒必要太過糾結。

  源點的流出量或匯點的流入量稱爲網絡流的值。在圖8.3中,網絡流的值是:

最大流

  圖3所示的網絡流的值是2,在這個網絡中是否存在另一個值更大的網絡流?

  既然網絡流的值取決於源點的流出量會或匯點的流入量,那麼只要使源點流出邊的容量或匯點流入邊的容量充分獲得利用,就能可以取得網絡流的最大值。這彷佛只是一個簡單的加法和比較運算:

  只要盡全力填滿油田的輸油管道就行了:

圖4

  遺憾的是,這種方式是錯誤的,它忽略了其它邊的容量,破壞了「流入等於流出」的守恆定律。以圖4爲例,C(v2v4)和C(v3v5)的總容量是3,不足以容納5個單位的石油。換句話說,下游的容量制約了上游的生產力。

  油田經過兩條管道輸出石油,其中的一條路徑是v1v2v4v6,當f(v1v2)=1時,v2v4是滿邊,它已經被充分利用,根據守恆定律,這條路徑上的總流量是1。相似地,另外一條路徑v1v3v5v6的總流量也是1。別忘了,咱們在v5v4處還有一個開關,打開這個開關,會獲得另外一條路徑v1v3v5v4v6,這將使更多的管道獲得充分利用,此時獲得了網絡中的最大流,Fmax=3:

基本數據結構

  如下是網絡流的基本數據結構,後續章節將反覆用到並擴充這個結構:

 1 class Edge():
 2     ''''''
 3     def __init__(self, v_from:int, v_to:int, cap:int, flow=0):
 4         '''
 5         :param v_from: 起點
 6         :param v_to:   終點
 7         :param cap:    容量
 8         :param flow:   流
 9         '''
10         self.v_from, self.v_to = v_from, v_to
11         self.cap, self.flow = cap, flow
12
13     def is_from(self, v):
14         ''' 是不是v頂點的流入邊 '''
15         return self.v_from == v
16
17     def is_to(self, v):
18         ''' 是不是v頂點的流出邊 '''
19         return self.v_to == v
20
21     def __str__(self):
22         return str(self.v_from) + '' + str(self.v_to)
23
24 class Network():
25     ''' st-網絡 '''
26     def __init__(self, V:list, E:list, s:int, t:int):
27         '''
28         :param V: 頂點集
29         :param E: 邊集
30         :param s: 原點
31         :param e: 匯點
32         :return:
33         '''
34         self.V, self.E, self.s, self.t = V, E, s, t
35
36     def get_from_edges(self, v):
37         '''
38         獲取頂點的流入邊
39         :param v: 頂點值
40         :return: 頂點的流入邊list
41         '''
42         return [edge for edge in self.E if edge.is_from(v)]
43
44     def get_to_edges(self, v):
45         '''
46         獲取頂點的流出邊
47         :param v: 頂點值
48         :return: 頂點的流出邊list
49         '''
50         return [edge for edge in self.E if edge.is_to(v)]
51
52     def flows_from(self, v):
53         '''v頂點的流入量 '''
54         edges = self.get_from_edges(v) # v的流入邊
55         return sum([e.flow for e in edges])
56
57     def flows_to(self, v):
58         '''v頂點的流出量 '''
59         edges = self.get_to_edges(v)  # v的流出邊
60         return sum([e.flow for e in edges])
61
62     def check(self, s, t):
63         ''' 源點的流出是否等於匯點的流入
64         :param s: 源點
65         :param t: 匯點
66         :return: s流出 = t流入,返回true
67         '''
68         return self.flows_to(s) == self.flows_from(t)
69
70     def display(self):
71         print('%-10s%-8s%-8s' % ('', '容量', ''))
72         for e in self.E:
73             print('%-10s%-10s%-8s' % (e, e.cap, e.flow))
74
75 V = [1, 2, 3, 4, 5, 6]
76 E = [Edge(1, 2, 2), Edge(1, 3, 3), Edge(2, 4, 1), Edge(3, 5, 2),
77      Edge(4, 6, 2), Edge(5, 4, 1), Edge(5, 6, 1)]
78 s, t = 1, 6
79 G = Network(V, E, s, t)
80 G.display()

 


 

    做者:我是8位的

  出處:http://www.cnblogs.com/bigmonkey

  本文以學習、研究和分享爲主,如需轉載,請聯繫本人,標明做者和出處,非商業用途! 

  掃描二維碼關注公衆號「我是8位的」

相關文章
相關標籤/搜索