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

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程语言 > c/c++ >内容正文

c/c++

warshall算法求传递闭包c++_【建模小课堂】图论算法

發布時間:2025/3/12 c/c++ 21 豆豆
生活随笔 收集整理的這篇文章主要介紹了 warshall算法求传递闭包c++_【建模小课堂】图论算法 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

圖論算法

圖論算法在計算機科學中扮演著很重要的角色,它提供了對很多問題都有效的一種簡單而系統的建模方式。很多問題都可以轉化為圖論問題,然后用圖論的基本算法加以解決。這類問題算法主要包括Dijkstra,Floyd,Prim,最短路、網絡流、二分圖等算法。

?背景?

哥尼斯堡(KOnigsberg)七橋問題

在哥尼斯堡的一個公園里,有七座橋將河中兩個島及島與河岸連接起來,問是否可能從這四塊陸地中任一塊出發,恰好通過每座橋一次,再回到起點

1736年,在經過一年的研究之后,29歲的歐拉提交了《哥尼斯堡七橋》的論文,圓滿解決了這一問題,同時開創了數學新一分支---圖論。

七橋問題在論文中,歐拉將七橋問題抽象出來,把每一塊陸地考慮成一個點,連接兩塊陸地的橋以線表示。并由此得到了如圖一樣的幾何圖形。?若我們分別用A、B、C、D四個點表示為哥尼斯堡的四個區域。這樣著名的“七橋問題”便轉化為是否能夠用一筆不重復地畫出過此七條線的問題了。若可以畫出來,則圖形中必有終點和起點,并且起點和終點應該是同一點,由于對稱性可知由B或C為起點得到的效果是一樣的,若假設以A為起點和終點,則必有一離開線和對應的進入線,若我們定義進入A的線的條數為入度,離開線的條數為出度,與A有關的線的條數為A的度,則A的出度和入度是相等的,即A的度應該為偶數。即要使得從A出發有解則A的度數應該為偶數,而實際上A的度數是5為奇數,于是可知從A出發是無解的。同時若從B或D出發,由于B、D的度數分別是3、3,都是奇數,即以之為起點都是無解的。上述理由可知,對于所抽象出的數學問題是無解的,即“七橋問題”也是無解的。
由此我們得到:歐拉回路關系

(對于一個連通圖,通常把從某結點出發一筆畫成所經過的路線叫做歐拉路。人們又通常把一筆畫成回到出發點的歐拉路叫做歐拉回路。具有歐拉回路的圖叫做歐拉圖。)


可知要使得一個圖形可以一筆畫,必須滿足如下兩個條件:
1. 圖形必須是連通的。
2. 圖中的“奇點”個數是0或2。

?引進概念?

圖:

二元組G(V,E)稱為圖(graph)。V為頂點(vertex) 或結點(node)的集。E為圖中邊的集合。

?點用數字0...n-1表示

?點對(u,v)稱為邊(edge)或稱弧
?子圖(subgraph):邊的子集和相關聯的點集

?帶權圖:可以給邊加權(weight),成為帶權圖,或加權圖(weightedgraph).權通常代表費用、距離等,可以是正數,也可以是負數

?有向圖:邊都是單向(unidirectional)的,因此邊(u,v)是有序數對.(最基本的圖通常被定義為“無向圖”,與之對應的則被稱為“有向圖”。兩者的區別在于,有向圖中的邊是有方向性的。下圖即是一個有向圖,邊的方向分別是:(1->2), (1-> 3), (3-> 1), (1->5), (2->3), (3->4), (3->5), (4->5), (1->6), (4->6)。

注意,圖中的邊(1->3)和(3->1)是不同的。有向圖和無向圖的許多原理和算法是相通的。)
有時用弧(arc)專指有向邊?

有時用弧(arc)專指有向邊

?一條路徑(path)是一個結點序列,路上的相鄰結點在圖上是鄰接的
?如果結點和邊都不重復出現,則稱為簡單路徑(simplepath).如果除了起點和終點相同外沒有重復頂點和邊,稱為圈(cycle).
?不相交路(disjoint path)表示沒有除了起點和終點以外的公共點的路.更嚴格的全圖:N個頂點的圖,有N(N-1)/2個節點于(u,v),若鄰接則改為非鄰接,若非鄰接則改為鄰接,得到的圖原圖的補圖

生成樹:
?樹:N個點,N-1條邊的連通圖(無環連通圖)
?生成樹:包含某圖G所有點的樹
?一個圖G是樹當且僅當以下任意一個條件成立
? ?G有V-1條邊,無圈

? ?G有V-1條邊,連通
? ?任意兩點只有唯一的簡單路徑
? ?G連通,但任意刪除一條邊后不連通

?最短路問題?

對一幅圖G,我們對每一條邊賦權w(e),成為一個賦權圖。H是G的一個子圖,則W(H)?= sigma(w(e)),也就是對每條邊的權求和。尋找從一個點a到另一個b的一個子圖,使得權和最小,即為最短路問題。

解法一:Dijkstra算法(僅適用于無負權邊的情況)

把頂點集合V分成兩組:?(1)S:已求出的頂點的集合(初始時只含有源點VO)?(2)V-S=T:尚未確定的頂點集合
將T中頂點按遞增的次序加入到S中,保證:
?(1)從源點VO到S中其他各頂點的長度都不大于從VO到T中任何頂點的最短路徑長度
?(2)每個頂點對應一個距離值
?S中頂點距離:從VO到此頂點的最短距離
?T中頂點距離:從V0到此頂點的只包括S中頂點作中間頂點的

算法圖解:
不斷求一個點集合中的每個點,和與他相鄰點最短路的最小值。我們還是從實例出發,更容易講解。求下面這個圖從A到L的最短路。


(1)
令a1 = A(便于標記),t(a1)?=?0(表示點a1到a的最短路),S={a1}(被選擇的點的集合),T =?0(空集?表示被選擇的最短路的邊集)。

(2)
求與S中的點a1與他相鄰的點的距離d,取點a2 = C使得距離最小。令S={a1,a2},T={AC}。

(3)
重復第二步,求S中的點a1,a2的相鄰點中(去除已選擇點),距離最小的那個,則為AB,CE。再取AB,CE中權和最小的一個,B,所以a3=B,令S={a1,a2,a3},T={AC,AB}。

持續下去,不斷尋找,S集合中的每個點與他相鄰點的最小距離,然后在這些最小距離中找到最小的那個加入到S中,同時加入相應的邊。

直到到達終點L為止。最后得到的最短路為:

此算法是多項式時間可求解的。

解法二:Floyd算法(插點法)
Floyd-Warshall算法(Floyd-Warshall algorithm)是解決任意兩點間的最短路徑的一種算法,可以正確處理有向圖或負權的最短路徑問題。

算法思想原理:
Floyd算法是一個經典的動態規劃算法。用通俗的語言來描述的話,首先我們的目標是尋找從點i到點j的最短路徑。從動態規劃的角度看問題,我們需要為這個目標重新做一個詮釋。從任意節點i到任意節點j的最短路徑不外乎2種可能,1是直接從i到j,2是從i經過若干個節點k到j。所以,我們假設Dis(i,j)為節點u到節點v的最短路徑的距離,對于每一個節點k,我們檢查Dis(i,k)?+ Dis(k,j)?< Dis(i,j)是否成立,如果成立,證明從i到k再到j的路徑比i直接到j的路徑短,我們便設置Dis(i,j)?= Dis(i,k)?+ Dis(k,j),這樣一來,當我們遍歷完所有節點k,Dis(i,j)中記錄的便是i到j的最短路徑的距離。
算法描述:
暑假,小哼準備去一些城市旅游。有些城市之間有公路,有些城市之間則沒有,如左圖。為了節省經費以及方便計劃旅程,小哼希望在出發之前知道任意兩個城市之前的最短路程。

上圖中有4個城市8條公路,公路上的數字表示這條公路的長短。請注意這些公路是單向的。我們現在需要求任意兩個城市之間的最短路程,也就是求任意兩個點之間的最短路徑。我們可以用一個4*4的矩陣(二維數組e)來存儲。比如1號城市到2號城市的路程為2,則設e[1][2]的值為2。2號城市無法到達4號城市,則設置e[2][4]的值為∞。另外此處約定一個城市自己到自己的路程也是0,例如e[1][1]為0。

如果求任意兩點之間的最短路徑,兩點之間可以直接到達但卻不是最短的路徑,要讓任意兩點(例如從頂點a點到頂點b)之間的路程變短,只能引入第三個點(頂點k),并通過這個頂點k中轉即a->k->b,才可能縮短原來從頂點a點到頂點b的路程。每個頂點都有可能使得另外兩個頂點之間的路程變短。

當任意兩點之間不允許經過第三個點時,這些城市之間最短路程就是初始路程。

在只允許經過1號頂點的情況下,任意兩點之間的最短路程更新為:

在只允許經過1號頂點的情況下,只需判斷e[i][1]+e[1][j]是否比e[i][j]要小即可。e[i][j]表示的是從i號頂點到j號頂點之間的路程。e[i][1]+e[1][j]表示的是從i號頂點先到1號頂點,再從1號頂點到j號頂點的路程之和。其中i是1~n循環,j也是1~n循環接下來繼續求在只允許經過1和2號兩個頂點的情況下任意兩點之間的最短路程。

我們需要在只允許經過1號頂點時任意兩點的最短路程的結果下,再判斷如果經過2號頂點是否可以使得i號頂點到j號頂點之間的路程變得更短。即判斷e[i][2]+e[2][j]是否比e[i][j]要小,在只允許經過1和2號頂點的情況下,任意兩點之間的最短路程更新為:

判斷e[i][2]+e[2][j]是否比e[i][j]要小。同理,繼續在只允許經過1、2和3號頂點進行中轉的情況下,求任意兩點之間的最短路程。任意兩點之間的最短路程更新為:

最后允許通過所有頂點作為中轉,任意兩點之間最終的最短路程為:

?最小生成樹問題?

同樣在一個連通賦權圖中,尋找一顆生成樹使得權和最小。

Kruskal算法(避圈法):
(1)在G中選取最小權邊e,并置邊數i=1;
(2)當i=n-1時結束,否則轉向(3);
(3設已選擇的邊為e,e2,.,e,在G中選不同于e,e2,.,e的邊e;+1,使得e;+是滿足與e,e,...,e不構成回路且權值最小的邊
(4)置為i+1,轉向(2)。
不斷尋找最小權的邊即可。
比如,尋找下圖的最小生成樹

結果如下

?網絡流問題?

如下圖所示,有一個頂點,稱為源點(source);還有一個頂點,稱為匯點(sink)。對于頂點,它最大流出2,因此它的最大流入為2,如下右圖所示。而他的最大流也就是5。

要想計算最大流,同樣可是使用前面的思想——分階段進行。令開始時所有邊都沒有流,如下中間圖所示。我們可以用殘余圖(residual graph)來表示對于每條邊還能再添加上多少流。對于每一條邊,可以從容量中減去當前的流而計算出殘留的流。

第一步:假設我們選擇路徑,此時會發出2個單位的流通過這條路徑的每一邊,如下中間圖所示。對比左圖,我們做如下約定:一旦注滿(使飽和)一條邊,例如到和到,就將這條邊從殘余圖(也就是中間圖)去掉,如下右圖所示。

第二步:接下來選擇路徑,此時也會發出2個單位的流通過這條路徑的每一邊,如下中間圖所示。同樣將殘余圖更新如下右圖所示。

第三步:從上圖的殘余圖中我們已經可以看出來最后一步的唯一一種走法了。

做如下圖所示更新。

很顯然無法走到,因此算法至此便終止了。因此正好5個單位的流是最大值。

如果一開始我們選擇了如下圖中間所示的走法,那么算法就會失敗了,因為路已經被堵死了。

為了使算法得以成功運作,那么就要讓流圖中具有以相反方向發送流的路徑,如下所示。那么對于如下右圖中的殘余圖而言,從d返回到a的便成了3而非4,這是因為從t流到d的流量是3個單位。現在在殘余圖中就有a和d之間有2個方向,或者還有1個單位的流可以從導向,或者是3個單位的流導向相反的反向,當然,我們也可以撤銷流。

緊接著如果通過到導入2個單位的流,算法就會從邊取走2個單位的流,更新流圖如下。

參考:

1.《數據結構》、《離散數學》、《算法導論》、《挑戰程序設計競賽》等書籍和必應、維基百科等網絡。
2.https://blog.csdn.net/u012469987/article/details/51319574
3.https://www.cnblogs.com/hxsyl/p/3270401.html
4.https://wk.baidu.com/view/343fcfe8172ded630b1cb6f9
5.https://wk.baidu.com/view/be1b0a7f58cfa1c7aa00b52acfc789eb172d9e07

總結

以上是生活随笔為你收集整理的warshall算法求传递闭包c++_【建模小课堂】图论算法的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。