遇到一道与最短路径相关的问题,题目如下:
如图:
各边权值已经给出在对应边上。假设邮递员只能按照有边的路线走,以起点为1,必须经过的点为3,5,最后返回到起点1的路径中,给出一个有效算法寻找一条最小权路径(路径中每条边权之和最小)!
注意:允许在某边上来回,或者经过某些点多次,或者某些点没有经过,但必须经过顶点3,5至少一次。
现在我们来分析:
从1出发,经过3、 5,回到1,要使路径最短,其实就是要决定先到3还是先到5。
首先,可以把这个图存储为邻接矩阵MatrixG[6][6],求任意两点之间的最短路径Distance[6][6]有很多方法,比如Dijkstra,Floyd_Warshall,就不多说了。
那么这道题的解就是:
MIN( Distance[1][3]+Distance[3][5]+Distance[5][1], Distance[1][5]+Distance[5][3]+Distance[3][1])。
而且,由于该图为无向图,所以有Distance[1][3]+Distance[3][5]+Distance[5][1] == Distance[1][5]+Distance[5][3]+Distance[3][1]。
那么这道题的答案就直接出来了。
但是,如果把题目扩展一下:
给定一个图,节点个数为VerticesNum;
已知的邻接矩阵MatrixG[VerticesNum][VerticesNum];
给定出发点Stard,目的地Destination;
给定若干个必须经过的节点(运行时输入);
怎样给出最佳的路径呢?
首先,可以根据Dijkstra或者Floyd Warshall算法得出最短路径矩阵Distance[VerticesNum][VerticesNum]。
然后,求解此问题,需要构架出一个搜索树,这颗搜索树试探了所有的走法。
假设出发点为a,必须经过i、j、k三个节点,终点为b。
那么求解次问题,需要试探A(3,3)种走法(A(3,3)为3取3的排列),即:
a i j k b ;
a i k j b ;
a j i k b ;
a j k i b ;
a k i j b ;
a k j i b ;
。
看那一种走法路程最短。
如何构建这颗搜索树呢?
可以用递归:将需要经过的节点组成一个链表PassingNodes,构建一个这样的函数route(Stard,Destination,PassingNodes)。
route函数的实现:
如果PassingNodes为空,那么直接返回Distance[Stard][Destination]。
如果PassingNodes非空,那么:
MiniWeight = INT_MAX;
for each i in PassingNodes:
remove node i form tPassingNodes;
Weight = Distance[Stard][i] + route(i,Destination,PassingNodes);
restore node i to PassingNodes;
if (MiniWeight > Weight)
{
MiniWeight = Weight;
RecordI = i;//记下路径
}
path.push(RecordI);//记下路径。
return MiniWeight;
这样的递归所形成的搜索树,正是对PassingNodes(假如PassingNodes中节点个数为n)中所有节点的所有排列的尝试,即n取n的排列。
程序的核心就可以这样实现了,至于优化,以后有空再考虑。
我写出了程序的具体实现,但分了好几个模块,就不贴出来了。
可以参考一些我的另一篇博客:
http://blog.csdn.net/wtewrw/archive/2010/05/06/5564454.aspx
不是同一个问题,但是做法有点类似。