[算法] 最短路径条数问题

匿名 (未验证) 提交于 2019-12-03 00:27:02

给定如图所示的无向连通图,假定图中所有边的权值均为1,显然,从源点A到终点T的最短路径有多条,求不同的最短路径数目。

权值相同的最短路径问题,则单源点Dijkstra算法退化为BFS广度优先算法, 使用Dijkstra算法只能求的到各个节点的最短路径,但不能求得最短路径的条数。假定起点为0,终点为N,数组step[0...N1]step[i]代表到第i个节点的最短路径长度,数组pathNum[0...N1]pathNum[i]代表到第i个节点的最短路径条数,首先:

  • step[0...N1]初始化为0
  • pathNum[0...N1]初始化为0
  • pathNum[0]为1,即起点到起点的路径数量为1

从当前节点i扩展到邻接节点j时:

  • step[j]为0,则表示从未到达过节点j,则:

    • step[j]=step[i]+1pathNum[j]=pathNum[i]
  • step[j]==step[i]+1,表示已经有从其他节点到达过节点j,并且路径长度和从节点i到节点j的路径长度相等,则已有到达j的路径数加上经过i到达j的路径数为当前从源点到达节点j的路径数量:

    • pathNum[j]+=pathNum[i]
  • step[j]>step[i]+1,则已有的经过其他节点到达节点j的路径长度要比经过节点i到达节点j路径长度要长,则需要更新到达节点j的路径长度和路径数量,即:

    • step[j]=step[i]+1pathNum[j]=pathNum[i]
  • 当扩展到节点N时,终止算法

借助广度优先搜索的思想遍历所有节点,具体实现如CalPathNum.hpp所示:

#ifndef CalPathNum_hpp #define CalPathNum_hpp  #include <stdio.h> #include <string.h> #include <queue>  const int nodeCnt = 16; int calculatePathNum(int graph[nodeCnt][nodeCnt]) {     int step[nodeCnt]; // step[i]表示到第i个节点的步数     int pathNum[nodeCnt]; // pathNum[i]表示到第i个节点的最短路径条数     memset(step, 0, sizeof(int)*nodeCnt);     memset(pathNum, 0, sizeof(int)*nodeCnt);     pathNum[0] = 1; // 起点到起点的路径数量为1     std::queue<int> q; // 广度优先搜索中保存当前到达的节点     q.push(0); // 首先到达起点     int from, i, s;     while (!q.empty()) {         from = q.front();         q.pop();         s = step[from] + 1; // 和from节点相邻的节点的路径长度         for (i = 1; i < nodeCnt; i++) { // 0是起点,不需要遍历             if (graph[from][i] == 1) { // 从from到i是连通的                 if (step[i] == 0 || step[i] > s) { // i节点从未到达过或发现更快的路径                     step[i] = s;                     pathNum[i] = pathNum[from];                     q.push(i); // 将和from相邻的节点入队,相当于广度优先搜索中form节点的下一层节点入队                 } else if(s == step[i]){ // 发现相同长度的路径                     pathNum[i] += pathNum[from];                 }             }         }     }     return pathNum[nodeCnt-1]; }  #endif /* CalPathNum_hpp */

测试代码如main.cpp:

#include "CalPathNum.hpp"  int main(int argc, const char * argv[]) {     // 测试最短路径条数     int graph[16][16];     memset(graph, 0, sizeof(int) * 16 * 16);     graph[0][1] = graph[0][4] = 1;     graph[1][5] = graph[1][0] = graph[1][2] = 1;     graph[2][1] = graph[2][6] = graph[2][3] = 1;     graph[3][2] = graph[3][7] = 1;     graph[4][0] = graph[4][5] = 1;     graph[5][1] = graph[5][4] = graph[5][6] = graph[5][9] = 1;     graph[6][2] = graph[6][5] = graph[6][7] = graph[6][10] = 1;     graph[7][3] = graph[7][6] = 1;     graph[8][9] = graph[8][12] = 1;     graph[9][8] = graph[9][13] = graph[9][10] = 1;     graph[10][9] = graph[10][14] = graph[10][11] = 1;     graph[11][10] = graph[11][15] = 1;     graph[12][8] = graph[12][13] = 1;     graph[13][9] = graph[13][12] = graph[13][14] = 1;     graph[14][10] = graph[14][13] = graph[14][15] = 1;     graph[15][11] = graph[15][14] = 1;     printf("%d\n", calculatePathNum(graph));      return 0; }

该算法事实上是广度优先搜索的一个应用

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!