#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