9.4 關系的閉包


9.4 關系的閉包

閉包的定義:

>關系R對於性質P的閉包,是加入最小數量的序偶,使得R恰好符合性質P所得到的集合 >R的閉包R1具有如下3個特點: >①. R1 包含 R >②. R1具有性質P >③. 如果R2具有性質P且R2包含R, 那么R2包含R1

就R的有向圖而言:

  1. 找其自反閉包(reflexive closure)

添加循環/閉環

  1. 找其對稱閉包(symmetric closure)

沿相反方向添加弧線(箭頭)

  1. 找其傳遞閉包(transitive closure)

如果a到b連通, 那么就添加從a到b的弧線(箭頭)

自反閉包(reflexive closure)
定理:R是定義在A上的關系,那么R的自反閉包r(R) = R∪△
如何獲得?

①. 在R的有向圖的所有頂點上添加閉環
②. 令R的鄰接矩陣的對角線上全為1

對稱閉包(symmetric closure)

定理①:R是定義在A上的關系,那么R的對稱閉包s(R) = R∪R-1
NOTE: R-1 = {(b, a) | (a, b) ∈ R}
NOTE: R-1的鄰接矩陣是R的鄰接矩陣的轉置,
即: MRT = MR-1

定理②:R是對稱的,當且僅當 R = R-1
NOTE:在對稱關系的有向圖中,用無向的邊來代替弧線(箭頭)

路徑(Paths)

假設R為定義在A上的關系,則R從a到b,長度為n的路徑可表示為以a為起始點,b為終點的一個有限序列π:
a, x1, x2, ..., xn-1, b;
其中,滿足:a R x1, x1 R x2, ..., xn-1 R b

例:

一些重要定義:

  • 環(cycle):

一條起始點和終點為相同頂點的路徑稱為:環(cycle)

  • Rn:

x Rn y表示,在R中存在一條或多條從x到y的路徑

  • 連通關系(connectivity relation) R*

R*包含的序偶對(a, b), 其中在R中至少存在一條從a到b的路徑

例:

一些重要定理:

  1. 如果R是定義在A上的關系,那么有:

    其中,⊙表示矩陣布爾乘法

證明:

  1. 當n>=2時,有:

證明:科學歸納法(略)

連通關系(The connectivity relation)

准備

  • 路徑的合成

令:
π1: a, x1, x2, … , xn-1, b
π2: b, y1, y2, … , ym-1, c
則π1與π2合成后的路徑為:
π2 o π1:a, x1, x2, … , xn-1, b, y1, y2, … , ym-, c

NOTE THE ORDER!!!(注意順序)

  • 傳遞閉包(Transitive closure)

①. 關系R的傳遞閉包是包含R的最小的傳遞關系。

②. R是傳遞的, 當且僅當,對於任何的n,均有Rn ⊆ 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 Rn ⊆ Sn

③. 如果R是傳遞的,那么Rn也是傳遞的
只需證明:(Rn)2 = (R2)n ⊂ Rn

④. 如果對於j>k, 有Rk = Rj, 那么對於某些n>=j, 有Rj+m = Rn
除了Rj之外,我們無法得到任何新的關系

  • 一個重要定理:

R為定義在A上的一個關系,那么R的閉包就等於R*

PROOF:我們必須證明,R

1). 是一個傳遞關系
2). 包含R
3). 是包含R的最小的傳遞關系

Proof of Part 1):

假設(x, y)和(y, z)都在R*中,只需證(x, z)也在R*
由R*定義知,一定存在m,n,使得(x, y)和(y, z)分別在Rm和Rn
又由復合定理,知:(x, z) ∈ RnoRm = Rm+n ⊆ R*
因此,R*是傳遞的

Proof of Part 2):

顯然.

Proof of Part 3):

最重要的結論:

  • 如果集合A的維數 = n,即|A|=n, 那么對於定義在A上的關系R,有:

  • 等價命題:對於k<=n<=m,有1)和2)同時成立

  • 1). Rm ⊆ Rk
  • 2). (a, b) ⊆ Rm → (a, b) ⊆ Rk

證明其實就是去掉環,此處略

沃舍爾算法(Warshall’s Algorithm)

需要知道:內部頂點(Interior vertices)

大致方法:

①. 將n個節點賦予順序為{a1, a2,…, an}, 並定義Wk = [tij]表示存在從第i個節點到第j個節點且僅通過內部節點{a1, a2,…, ak}這k個節點(這些節點可選可不選,但除此之外的節點都不能選)的路徑連通,並記為“1”, 否則記為“0”
②. W0 = 初始鄰接矩陣MR
③. 利用Wk-1來計算Wk
④. 得連通矩陣MR* = Wn

計算具體Wk的做法:

對於Wk中的tab
①. 如果Wk-1的sab == ‘1’,即僅利用{a1, a2,…, ak-1}這k-1個點(當然包括第a和第b個頂點)就能使a連通到b,那么Wk的tab直接 = ‘1’
②. 如果Wk-1的sab == ‘0’, 那么要使僅用{a1, a2,…, ak}這n個點從a連通到b, 則:
只需存在一個m(1 <= m <= k-1),使得在Wk-1中,有:sam == “1”並且smb == “1”(在Wk-1中,節點a到m連通,節點m到b連通, 那么在Wk中,節點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算法:用Wk的tab表示點a到點b只用{a1, a2,…, ak}這k個點和a與b所能達到的最短路徑值,和Warshall算法一樣,用W[k-1]來計算W[k],而Wn即為所有兩點之間(即多源)最短路徑的答案

  • flody算法是用來求圖的多源最短路徑的算法,復雜度也為O(n^3)
  • 將連通的邊權定為有限值(如1),不連通的邊權定為∞,便可以用flody算法求所有點的連通性(如i, j兩個節點的最短路徑為有限值即連通)
  • Warshall算法和flody算法都能用動態規划的想法來理解:動態規划深刻理解flody
  • 為什么 Dijkstra 不能提出 floyd 算法?因為他的名字是 ijk 而不是 kij


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM