#9.4 關係的閉包html
###閉包的定義: <font size=3>算法
關係R對於性質P的閉包,是加入最小數量的序偶,使得R剛好符合性質P所獲得的集合
R的閉包R<sub>1</sub>具備以下3個特色:
①. R<sub>1</sub> 包含 R
②. R<sub>1</sub>具備性質P
③. 若是R<sub>2</sub>具備性質P且R<sub>2</sub>包含R, 那麼R<sub>2</sub>包含R<sub>1</sub>數組
###就R的有向圖而言:閉包
- 找其自反閉包(reflexive closure)
添加循環/閉環flex
- 找其對稱閉包(symmetric closure)
沿相反方向添加弧線(箭頭)優化
- 找其傳遞閉包(transitive closure)
若是a到b連通, 那麼就添加從a到b的弧線(箭頭)url
<font color=#00ffff>自反閉包(reflexive closure)</font>
定理:R是定義在A上的關係,那麼R的自反閉包r(R) = R∪△
如何得到?.net
①. 在R的有向圖的全部頂點上添加閉環
②. 令R的鄰接矩陣的對角線上全爲13d
<font color=#00ffff>對稱閉包(symmetric closure)</font>code
定理①:R是定義在A上的關係,那麼R的對稱閉包s(R) = R∪R<sup>-1</sup>
NOTE: R<sup>-1</sup> = {(b, a) | (a, b) ∈ R}
NOTE: R<sup>-1</sup>的鄰接矩陣是R的鄰接矩陣的轉置,
即: M<sub>R</sub><sup>T</sup> = M<sub>R<sup>-1</sup></sub>
定理②:R是對稱的,當且僅當 R = R<sup>-1</sup>
NOTE:在對稱關係的有向圖中,用無向的邊來代替弧線(箭頭)
##路徑(Paths)
假設R爲定義在A上的關係,則R從a到b,長度爲n的路徑可表示爲以a爲起始點,b爲終點的一個有限序列π:
a, x<sub>1</sub>, x<sub>2</sub>, ..., x<sub>n-1</sub>, b;
其中,知足:a R x<sub>1</sub>, x<sub>1</sub> R x<sub>2</sub>, ..., x<sub>n-1</sub> R b
例:
####一些重要定義:
- 環(cycle):
一條起始點和終點爲相同頂點的路徑稱爲:環(cycle)
- R<sup>n</sup>:
x R<sup>n</sup> y表示,在R中存在一條或多條從x到y的路徑
- 連通關係(connectivity relation) R<sup>*</sup>
R<sup>*</sup>包含的序偶對(a, b), 其中在R中至少存在一條從a到b的路徑
例:
####一些重要定理:
- 若是R是定義在A上的關係,那麼有:
其中,⊙表示矩陣布爾乘法
證實:
- 當n>=2時,有:
證實:科學概括法(略)
##連通關係(The connectivity relation)
<font size=4 color=#00ffff>準備</font>
- 路徑的合成
令:
π<sub>1</sub>: a, x<sub>1</sub>, x<sub>2</sub>, … , x<sub>n-1</sub>, b
π<sub>2</sub>: b, y<sub>1</sub>, y<sub>2</sub>, … , y<sub>m-1</sub>, c
則π<sub>1</sub>與π<sub>2</sub>合成後的路徑爲:
π<sub>2</sub> o π<sub>1</sub>:a, x<sub>1</sub>, x<sub>2</sub>, … , x<sub>n-1</sub>, b, y<sub>1</sub>, y<sub>2</sub>, … , y<sub>m-</sub>, cNOTE THE ORDER!!!(注意順序)
- 傳遞閉包(Transitive closure)
①. 關係R的傳遞閉包是包含R的最小的傳遞關係。
②. R是傳遞的, 當且僅當,對於任何的n,均有R<sup>n</sup> ⊆ R(結論來自9.1)
③. 若是傳遞閉包存在一條從x到y的路徑,那麼必定有從x直接到y的弧線(箭頭)
- 傳遞閉包裏有用的一些結論:
①. If A ⊆ B and C ⊆ B, then (A∪C) ⊆ B.
②. If R ⊆ S and T ⊆ U then (RoT) ⊆ (SoU).
推論: If R ⊆ S then R<sup>n</sup> ⊆ S<sup>n</sup>
③. 若是R是傳遞的,那麼R<sup>n</sup>也是傳遞的 只需證實:(R<sup>n</sup>)<sup>2</sup> = (R<sup>2</sup>)<sup>n</sup> ⊂ R<sup>n</sup>
④. 若是對於j>k, 有R<sup>k</sup> = R<sup>j</sup>, 那麼對於某些n>=j, 有R<sup>j+m</sup> = R<sup>n</sup>
除了R<sup>j</sup>以外,咱們沒法獲得任何新的關係
- 一個重要定理:
R爲定義在A上的一個關係,那麼R的閉包就等於R<sup>*</sup>
PROOF:咱們必須證實,R<sup>∞</sup>
1). 是一個傳遞關係
2). 包含R
3). 是包含R的最小的傳遞關係
Proof of Part 1):
假設(x, y)和(y, z)都在R<sup>*</sup>中,只需證(x, z)也在R<sup>*</sup>中
由R<sup>*</sup>定義知,必定存在m,n,使得(x, y)和(y, z)分別在R<sup>m</sup>和R<sup>n</sup>中
又由複合定理,知:(x, z) ∈ R<sup>n</sup>oR<sup>m</sup> = R<sup>m+n</sup> ⊆ R<sup>*</sup>
所以,R<sup>*</sup>是傳遞的
Proof of Part 2):
顯然.
Proof of Part 3):
###最重要的結論:
-
若是集合A的維數 = n,即|A|=n, 那麼對於定義在A上的關係R,有:
-
等價命題:對於k<=n<=m,有1)和2)同時成立
- 1). R<sup>m</sup> ⊆ R<sup>k</sup>
- 2). (a, b) ⊆ R<sup>m</sup> → (a, b) ⊆ R<sup>k</sup>
證實其實就是去掉環,此處略
##沃舍爾算法(Warshall’s Algorithm)
須要知道:內部頂點(Interior vertices)
###大體方法:
①. 將n個節點賦予順序爲{a<sub>1</sub>, a<sub>2</sub>,…, a<sub>n</sub>}, 並定義W<sub>k</sub> = [t<sub>ij</sub>]表示存在從第i個節點到第j個節點且僅經過內部節點{a<sub>1</sub>, a<sub>2</sub>,…, a<sub>k</sub>}這k個節點(這些節點可選可不選,但除此以外的節點都不能選)的路徑連通,並記爲「1」, 不然記爲「0」
②. W<sub>0</sub> = 初始鄰接矩陣M<sub>R</sub>
③. 利用W<sub>k-1</sub>來計算W<sub>k</sub>
④. 得連通矩陣M<sub>R<sup>*</sup></sub> = W<sub>n</sub>
###計算具體W<sub>k</sub>的作法:
對於W<sub>k</sub>中的t<sub>ab</sub>
①. 若是W<sub>k-1</sub>的s<sub>ab</sub> == ‘1’,即僅利用{a<sub>1</sub>, a<sub>2</sub>,…, a<sub>k-1</sub>}這k-1個點(固然包括第a和第b個頂點)就能使a連通到b,那麼W<sub>k</sub>的t<sub>ab</sub>直接 = ‘1’
②. 若是W<sub>k-1</sub>的s<sub>ab</sub> == ‘0’, 那麼要使僅用{a<sub>1</sub>, a<sub>2</sub>,…, a<sub>k</sub>}這n個點從a連通到b, 則:
只需存在一個m(1 <= m <= k-1),使得在W<sub>k-1</sub>中,有:s<sub>am</sub> == 「1」而且s<sub>mb</sub> == 「1」(在W<sub>k-1</sub>中,節點a到m連通,節點m到b連通, 那麼在W<sub>k</sub>中,節點a到b連通)
例:
核心代碼:
for(int k = 1; k <= N; k++) { for(int i = 1; i <= N; i++) { for(int j = 1; j <= N; j++) { if(W[k-1][i][j]=='1') { W[k][i][j] = 1; } else if(W[k-1][i][k]=='1'&&W[k-1][k][j]=='1') { W[k][i][j] = 1; } } } }
時間複雜度:O(n^3)
空間複雜度:O(n^3)
其實因爲W[k]只與W[k-1]有關,能夠只用二維數組來表示W[k-1],而後更新W[k]的時候直接覆蓋到這個數組便可將空間複雜度壓縮成O(n^2)
實戰:Cow Contest
思路:只需求以這些牛組成有向圖的傳遞閉包(用連通矩陣表示),再判斷每一個節點的入度+出度是否等於n-1,來判斷每頭牛可否確認排名
AC代碼:
#include <stdio.h> int main(void) { int n, m, a, b; //n頭牛, m個關係 scanf("%d %d",&n,&m); int W[n+1][n+1]; for(int i = 1; i <= n; i++) for(int j = 1; j <= n; j++) W[i][j] = 0; for(int i = 1; i <= m; i++) { scanf("%d %d",&a,&b); W[a][b] = 1; //初始賦值W[0] } //這裏即只需用一個二維數組表示W[k-1],而後將W[k]覆蓋到W[k-1]這個二維數組上,使得空間複雜度爲:O(n^2) for(int k = 1; k <= n; k++) { for(int i = 1; i <= n; i++) { for(int j = 1; j <= n; j++) { //if(W[i][j]==1) // 表明第一種狀況,徹底能夠省去 // W[i][j] = 1; if(W[i][j]==0) //表明第二種狀況 { if(W[i][k]==1&&W[k][j]==1) W[i][j] = 1; } } } } int sumdu = 0, ans = 0; for(int i = 1; i <= n; i++) //判斷每一個點的入度和出度之和是否爲n-1 { sumdu = 0; for(int j = 1; j <= n; j++) { if(W[i][j]==1||W[j][i]==1) sumdu++; } if(sumdu==n-1) ans++; } printf("%d\n",ans); return 0; }
##OTHERS
###解決最短路徑問題有幾個經常使用的算法:
- ①. dijkstra算法,最經典的單源最短路徑算法
- ②. bellman-ford算法,容許負權邊的單源最短路徑算法
- ③. spfa,實際上是bellman-ford+隊列優化,其實和bfs的關係更密一點
- ④. floyd算法,經典的多源最短路徑算法
而Warshall算法和flody算法最具殊途同歸之妙:
flody算法:<font color=#00ffff>用W<sub>k</sub>的t<sub>ab</sub>表示點a到點b只用{a<sub>1</sub>, a<sub>2</sub>,…, a<sub>k</sub>}這k個點和a與b所能達到的最短路徑值,和Warshall算法同樣,用W[k-1]來計算W[k],而W<sub>n</sub>即爲全部兩點之間(即多源)最短路徑的答案</font>
- flody算法是用來求圖的多源最短路徑的算法,複雜度也爲O(n^3)
- 將連通的邊權定爲有限值(如1),不連通的邊權定爲∞,即可以用flody算法求全部點的連通性(如i, j兩個節點的最短路徑爲有限值即連通)
- Warshall算法和flody算法都能用動態規劃的想法來理解:動態規劃深入理解flody
- 爲何 Dijkstra 不能提出 floyd 算法?由於他的名字是 ijk 而不是 kij