9.4 关系的闭包

#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的有向图而言:闭包

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

添加循环/闭环flex

  1. 找其对称闭包(symmetric closure)

沿相反方向添加弧线(箭头)优化

  1. 找其传递闭包(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的路径

例:

####一些重要定理:

  1. 若是R是定义在A上的关系,那么有:
    其中,⊙表示矩阵布尔乘法

证实:

  1. 当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>, c

NOTE 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
相关文章
相关标签/搜索