由于本篇博文的图不能正常显示,故将本篇博文的底稿上传。下载地址为:https://files.cnblogs.com/finallyliuyu/allpathbetweentwonodes.rar

希望能对大家有用。另外需要指出的是:我的这个求两点之间所有路径的算法并不高效,但是可以保证正确,无论是有向图,还是无向图都可以使用。

作者:finallyly 出处:技术(如若转载请注明作者和出处)

最近在实现一个算法,算法之内有一个子算法是求有向图内两个定点(原点和目的点)之间的全部路径。在网上翻阅了大部分资料,发现给出的算法和代码要么只能解决DAG(有向无环图)的两定点之间所有路径问题,要么就是算法本身存在若干漏洞,连DAG图也无法解决。花费了一天的时间,自己写了个求简单有向图中(包括dag和非dag)两定点之间所有路径的算法,特共享出来。

文章将按如下组织,首先给出path的定义,其次给出dag的定义,然后给出算法的伪代码,之后是算法的C++实现以及实验结果。

1 Path的定义

Path的定义是建立在walk,基础上的。参见Bondy的《Graph Theory With Applications》

 

由上面的定义,我问可以得出path是一个结点和边交叠出现的序列,并且在这个序列中结点不能重复,边也不能重复。

 

2 DAG的定义

DAG(Directed Acyclic Graph):即不存在环路的有向图。或者说是DFS过程中不出现回边(backc edge)的图。如图2-1就是一个DAG。更一般的有向图见图2-2

C0PT(L)6X@D71L}Y]3K(4C2

2‑1 DAG

++++++++++++++++++++++++++++++++++++++

第1条路径是:0-->1-->4-->11

第2条路径是:0-->1-->3-->11

第3条路径是:0-->1-->2-->6-->10-->11

第4条路径是:0-->1-->2-->6-->9-->11

第5条路径是:0-->1-->2-->5-->8-->11

第6条路径是:0-->1-->2-->5-->7-->11

++++++++++++++++++++++++++++++++++++++

}WK[LS69X1]O9Z`0CY[B{(2

2‑2 Digraph

该图对应的矩阵型存储格式为:

Q5GPCJCK94}`}LVT6LQA@G5

它的路径有:

++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

第一条路径:0->1->2->3->4

第二条路径:0->1->2->4

第三条路径:0->1->3->2->4

第四条路径:0->1->3->4

第五条路径:0->1->4

第六条路径:0->2->1->3->4

第七条路径:0->2->1->4

第八条路径:0->2->3->1->4

第九条路径:0->2->3->4

第十条路径:0->2->4

第十一条路径:0->3->1->2->4

第十二条路径:0->3->1->4

第十三条路径:0->3->2->1->4

第十四条路径:0->3->2->4

第十五条路径:0->3->4

+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

3 算法设计

待求解问题是“求原点和目的点之间的全部路径”,求解问题的第一步,我们需要确定这是一个P问题还是NP问题。对于P问题,可以直接设计算法;对于NP问题,则需要一些近似手段。值得庆幸的是这是一个P问题。算法最大复杂度为

E_5P4C~D[8~U60H`_S)@U~E

证明如下:

假定有向图为N个节点的简单完全图,即每个节点都与其他N-1个节点有边相连。起始结点和结束节点确定,那么我们需要排列中间的N-2个节点,对于第一个非固定的节点,它有N-2种可能取值。。。以此类推得到上述答案。

求两定点之间的全部路径,其根本是一个涉及到搜索和回溯的问题。我们设计算法时所关心的首要问题是:按照何种顺序搜索和回溯才能保证路径可以不重不漏地被全部找到。

如下是算法设计部分

图的存储结构:邻接矩阵。Arcs

工作结构:结点栈 mystack;

状态保存结构:

(1) VertexStatus[]={0,0,0,1,1,…}。当结点未进栈或者已经出栈,则其对应的状态为0,否则状态为1;

(2) ArcStatus[][]={0,0,1,0,1…..}当且仅当边的两个结点都在栈外时,边的状态才为0,否则为1。

注意我们只所以设计如上结点、边两个状态存储结构,就是依据于path的定义,结点不重复,边不重复。具有边状态存储结构,也是我的算法与其他算法根本上的不同。

不失一般性,我们假设原点的编号最小为0,目标点的编号最大N。我们的问题转换成了,求最小编号的节点与最大编号的节点之间的所有路径。

Intial :

Paths={}//路径集合

VertexStatus[]={0};//全部置0

ArcStatus[][]={0};////全部置0

mystack.push(0);

VertexStatus[0]=1;

While(!mystack.empty())

{

Int elem= mystack.top();//获得栈顶元素

if(elem==N)//找到了一条路径

{

path=Traverse(mystack);

Paths.add(path);

VertexStatus[elem]=0;

UpdateArcStatus();//更新ArcStatus[][],使得所有两个端点都不在栈内的边的状态为0

mystack.pop();//移除栈顶元素

}

else

{

i=0;

For(;i<N;i++)

{ if(VertexStatus[i]=0&&ArcStatus[elem][i]=0&&Arcs.contain(elem,i))

{

VertexStatus[i]=1;

ArcStatus[elem][i]=1;

Mystack.push(i);//入栈

break;

}

}

if(i=N)//该节点没有符合要求的后续节点

{

VertexStatus[elem]=0;

UpdateArcStaus();////更新ArcStatus[][],使得所有两个端点都不在栈内的边的状为0

Mystack.pop();//出栈

}

}

}

posted on 2011-04-18 10:00  finallyly  阅读(29998)  评论(24编辑  收藏  举报