有向图Kosaraju算法的正确性证明

来源:互联网 发布:英魂之刃开挂软件 编辑:程序博客网 时间:2024/05/04 15:36

Kosaraju的工作过程是:
1.在给定的一副有向图G中,首先取得它的反向图,然后计算反向图的逆后续排列
2.在G中进行标准的深度优先搜索,但是搜索的顺序是按照第一步中计算得出的顺序而非标准顺序来访问所有未被标记的顶点
3.在构造函数中,所有在同一个递归dfs()调用中被访问到的顶点都在同一个强连通分量中,可以通过标记来把它们取出来。

命题:
使用深度优先搜索查找给定有向图G的反向图G1,根据G1计算出所有顶点的逆后续排列,然后根据该逆后续排列去深度优先处理有向图G,其构造函数中的每一次递归调用所标记的顶点都在同一个联通分量中。

证明过程:
1.首先要用反证法证明”每个和s强联通的顶点v都会在dfs(G,s)的过程中被访问到”。那么现在假设有一个和s强联通的v顶点在dfs(G,s)的过程中没有被访问到,因为存在s到v的路径那么说明在此之前该v顶点已经被标记过了,但又因为是强联通所以也存在v到s的路径,所以之前访问到v的时候s也一定被标记过了,所以dfs(G,s)不会被执行。这和之前相互矛盾,所以该命题得证。

2.在进行第二步的证明之前我们先看一看一幅图所有顶点的逆后序顺序的性质,逆后序是在对图进行深度优先搜索的时候把顶点存入一个栈中,部分代码如下:

void dfs(Digraph G,int v){    marked[v]=true;    for(int w:G.adj(v))        if(!marked[w])            dfs(G,w);    reversePost.push(v);}

不难得出,逆后序的这种行为会导致在reversePost这个栈中,任意一个子节点存放皆后于父节点,也就是说所有只有当所有子节点都入栈了,父节点才入栈(这也正是拓扑排序要用到逆后序的原因)。
清楚这一点后我们开始第二步的证明:
证明”构造函数调用的dfs(G,s)所到达的任意顶点v都必然是和s强联通的”
设v为dfs(G,s)调用中到达的某个顶点,那么G中必然存在一条从s到v的路径,因此现在只需证明G中有一条v到s的路径即可,这等价于证明反向图G1中存在一条从s到v的路径。证明的核心在于,按照逆后续进行的深度优先搜索意味着,在G1中进行的深度优先搜索中,dfs(G,v)必然在dfs(G,s)结束之前就结束了,这样dfs(G,v)的调用就只有两种情况:
①:调用在dfs(G,s)之前(并且也在dfs(G,s)结束之前结束)
②:调用在dfs(G,s)之后(并且也在dfs(G,s)结束之前结束)
第一种情况是不可能出现的,第一步已经证明了。而第二种情况则说明在G1中存在一条从s到v的路径。证明完毕。

ps:【本蒟蒻希望尽快把算法4刷完…】

1 0
原创粉丝点击