在了解了1-最短路径的计算方式后,我们看看N-最短路径的计算。
N-最短路径的计算方式与1-最短路径基本相同,只是在记录所有可达路径时,要保留最短的前N个结果。让我们仍然以上篇文章的案例来看看如何实现N-最短路径的运算。
1、数据表示
这里我们仍然沿用前文例子,对下图求N-最短路径,每条边的权重已经在图中标注出来了。
(图一)
2、运算过程
仍然象1-最短路径一样,计算出每个结点上可达N-最短路的PreNode。我们这里以2-最短路径为例:
1)首先计算出每个结点上所有可达路径的可能路径长度并按从小到大排序。
2)根据排序结果取前2种路径长度并分别记录进各结点的PreNode队列。如下图:
(图二)
在该图中,到达1号、2号、3号结点的路径虽然有多条,但长度只有一种长度,但到达4号“D”结点的路径长度有两种,即长度可能是3也可能是4,此时在“最短路”处(index=0)记录长度为3时的PreNode,在“次短路”处(index=1)处记录长度为4时的PreNode,依此类推。
值得注意的是,此时用来记录PreNode的坐标已经由前文求“1-最短路径”时的一个数(ParentNode值)变为2个数(ParentNode值以及index值)。
如图二所示,到达6号“末”结点的次短路径由两个ParentNode,一个是index=0中的4号结点,一个是index=1的5号结点,它们都使得总路径长度为6。
3、具体实现
在具体实现上述算法时,首先要求得所有可能路径的长度,这在SharpICTCLAS中是通过一个EnQueueCurNodeEdges方法实现的,上篇文章给出了它的简化版本的代码,这里将完整的求N-最短路径的EnQueueCurNodeEdges方法代码放上来:
// 将所有到当前结点(nCurNode)可能的边根据eWeight排序并压入队列
//====================================================================
private static void EnQueueCurNodeEdges(ref CQueue queWork, int nCurNode)
{
int nPreNode;
double eWeight;
ChainItem<ChainContent> pEdgeList;
queWork.Clear();
pEdgeList = m_apCost.GetFirstElementOfCol(nCurNode);
// Get all the edges
while (pEdgeList != null && pEdgeList.col == nCurNode)
{
nPreNode = pEdgeList.row; // 很特别的命令,利用了row与col的关系
eWeight = pEdgeList.Content.eWeight; //Get the eWeight of edges
for (int i = 0; i < m_nValueKind; i++)
{
// 第一个结点,没有PreNode,直接加入队列
if (nPreNode == 0)
{
queWork.EnQueue(new QueueElement(nPreNode, i, eWeight));
break;
}
// 如果PreNode的Weight == Predefine.INFINITE_VALUE,则没有必要继续下去了
if (m_pWeight[nPreNode - 1][i] == Predefine.INFINITE_VALUE)
break;
queWork.EnQueue(new QueueElement(nPreNode, i, eWeight + m_pWeight[nPreNode - 1][i]));
}
pEdgeList = pEdgeList.next;
}
}
这里的m_nValueKind就是你希望N-最短路径保留几种路径的结果。
当m_nValueKind=2时,我们求得了2-最短路径,路径长度有两种,分别长度为5和6,而路径总共有6条,如下:
最短路径:
- 0, 1, 3, 6,
- 0, 1, 2, 3, 6,
- 0, 1, 2, 4, 5, 6,
========================
次短路径
- 0, 1, 2, 4, 6,
- 0, 1, 3, 4, 5, 6,
- 0, 1, 2, 3, 4, 5, 6,
4、求解N-最短路径
N-最短路径的最终输出与上篇文章完全一致,仍然是借助堆栈完成的。只不过根据index的取值的不同,分多次完成压栈与出栈的操作而已。此处就不再重复,感兴趣的可以再看看上一篇文章。
- 小结
1)N-最短路径中用来记录PreNode的坐标由前文求“1-最短路径”时的一个数(ParentNode值)变为2个数(ParentNode值以及index值)。
2)N-最短路径并不意味着求得得路径只有N条。
3)文中只演示了2-最短路径,但可以推广到N-最短路径。程序求得的3-最短路径中,最长的路径为:(0, 1, 3, 4, 6)与(0, 1, 2, 3, 4, 6),它们的长度都是7。