一、理论篇

\quad 如下图所示,是一个有7个顶点的图,每条边权值均为1,试问从点0点6,有多少条最短路径呢,分别是什么?

\quad 我们可以直观的看出来,一共有4条最短路径,分别是

  • 0->1->4->6
  • 0->2->4->6
  • 0->2->5->6
  • 0->3->5->6

\quad 那么问题来啦,我们要如何记录下这些所有的最短路径呢,以前在只需记录一条最短路径的情况下,我们只需要一个数组来记录当前节点的前驱节点是什么,最后再通过不断的获取当前节点的前驱节点来获得路径。在记录所有的最短路径时,我们需要建立一个二维数组,用于存储当前节点可以由哪些节点得到,用最短路算法得到这样一个二维数组后,我们便可以通过DFS得到所有路径。
\quad 具体而言,针对上面的图,我们建立一个二维数组vector<int> pre[7]来存放0到每个节点的最短路可以由哪些前驱节点得到,那么可知

  • pre[0] = {}
  • pre[1] = {0}
  • pre[2] = {0}
  • pre[3] = {0}
  • pre[4] = {1, 2}
  • pre[5] = {2, 3}
  • pre[6] = {4, 5}

\quad 这样,我们对pre进行dfs,就可以得到这样一棵递归树。这棵树就是我们的解空间。

二、代码篇

\quad 现在我们来一步一步写程序实现这个求解过程,主要分为两步,第一步是用Dijistra得到pre数组,第二步是对pre进行DFS获得所有路径。首先,我们看看在Dijistra的最优子结构中,pre如何得到和更新。

if(dis[v] > dis[u] + G[u][v])
{dis[v] = dis[u] + G[u][v];pre[v].clear();  //这里要记得clearpre[v].push_back(u);
}
else if(dis[v] == dis[u] + G[u][v])
{pre[v].push_back(u);
}

\quad 如果 dis[u] + G[u][v] < dis[v], 说明以u为中介点可以使 dis[v]更优,此时需要令v的前驱结点为u。并且即便原先 pre[v]中已经存放了若干结点,此处也应当先清空,然后再添加u。之后,如果 dis[u] + G[u][v] = dis[v], 说明以 u 为中介点可以找到一条距离相同的路径,因此v的前驱结点需要在原先的基础上添加上 u 结点(而不必先清空pre[v])。完整的Dijistra如下,我用的是队列优化的Dijistra,不优化的话直接将上述最优子结构加在普通的Dijistra上就行:

#include <iostream>
#include <vector>
#include <queue>
#include <cstring>
#include <algorithm>
using namespace std;const int maxn = 1e4+10;
vector<pair<int, int> > E[maxn];
vector<int> pre[maxn], temp;
int vis[maxn], dis[maxn];
void dijstra(int s)
{fill(dis, dis+maxn, 0x3f3f3f3f);dis[s] = 0;priority_queue<pair<int, int> > q;q.push(make_pair(0, s));while(!q.empty()){int u = q.top().second;q.pop();if(vis[u]==1) continue;vis[u] = 1;for (int i = 0; i < E[u].size(); ++i){int v = E[u][i].first, w = E[u][i].second;if(dis[v]>dis[u]+w){dis[v] = dis[u]+w;pre[v].clear();pre[v].push_back(u);if(vis[v]==0) q.push(make_pair(-dis[v], v));}else if(dis[v]==dis[u]+w){pre[v].push_back(u);if(vis[v]==0) q.push(make_pair(-dis[v], v));}}}
}
int main(int argc, char const *argv[])
{int N, M, s, t;  // 点数,边数,起点,终点cin >> N >> M >> s >> t;while(M--){int u, v, w;cin >> u >> v >> w;E[u].push_back(make_pair(v, w));E[v].push_back(make_pair(u, w));}dijstra(s);for (int i = 0; i < N; ++i){printf("pre[%d]: ", i);for (int j = 0; j < pre[i].size(); ++j){printf("%d ", pre[i][j]);}printf("\n");}return 0;
}
/*
输入
7 9 0 6
0 1 1
0 2 1
0 3 1
1 4 1
2 4 1
2 5 1
3 5 1
4 6 1
5 6 1
*/


\quad 第二部分是对pre进行dfs,获得所有的最短路径。我们从终点t开始dfs,当终点t等于起点s时输出路径,否则取出其前驱节点继续dfs。在程序里面我将注释写得很清楚啦

void dfs(int s, int t)
{if(s==t) // 当到达起始节点,表明找到啦一条路径,输出{temp.push_back(t);// 输出路径,若不想输出可以用一个二维vector存储每条路径,注意是倒序for (int i = temp.size()-1; i >= 0; i--){cout << temp[i] << " ";}cout << endl;temp.pop_back(); // 将刚加入的节点删除return;}temp.push_back(t);  // 将当前访问的节点加入临时路径temp后面for (int i = 0; i < pre[t].size(); ++i){dfs(s, pre[t][i]);}temp.pop_back();  // 遍历完v点所有的前驱节点,将v删除
}

\quad 总的求解程序如下

#include <iostream>
#include <vector>
#include <queue>
#include <cstring>
#include <algorithm>
using namespace std;const int maxn = 1e4+10;
vector<pair<int, int> > E[maxn];
vector<int> pre[maxn], temp;
int vis[maxn], dis[maxn];
void dijstra(int s)
{fill(dis, dis+maxn, 0x3f3f3f3f);dis[s] = 0;priority_queue<pair<int, int> > q;q.push(make_pair(0, s));while(!q.empty()){int u = q.top().second;q.pop();if(vis[u]==1) continue;vis[u] = 1;for (int i = 0; i < E[u].size(); ++i){int v = E[u][i].first, w = E[u][i].second;if(dis[v]>dis[u]+w){dis[v] = dis[u]+w;pre[v].clear();pre[v].push_back(u);if(vis[v]==0) q.push(make_pair(-dis[v], v));}else if(dis[v]==dis[u]+w){pre[v].push_back(u);if(vis[v]==0) q.push(make_pair(-dis[v], v));}}}
}
void dfs(int s, int t)
{if(s==t) // 当到达起始节点,表明找到啦一条路径,输出{temp.push_back(t);// 输出路径,若不想输出可以用一个二维vector存储每条路径for (int i = temp.size()-1; i >= 0; i--){cout << temp[i] << " ";}cout << endl;temp.pop_back(); // 将刚加入的节点删除return;}temp.push_back(t);  // 将当前访问的节点加入临时路径temp后面for (int i = 0; i < pre[t].size(); ++i){dfs(s, pre[t][i]);}temp.pop_back();  // 遍历完v点所有的前驱节点,将v删除
}
int main(int argc, char const *argv[])
{int N, M, s, t;cin >> N >> M >> s >> t;while(M--){int u, v, w;cin >> u >> v >> w;E[u].push_back(make_pair(v, w));E[v].push_back(make_pair(u, w));}dijstra(s);dfs(s, t);return 0;
}/*
7 9 0 6
0 1 1
0 2 1
0 3 1
1 4 1
2 4 1
2 5 1
3 5 1
4 6 1
5 6 1
*/

\quad 运行结果如下:

求图中两点间的所有的最短路径相关推荐

  1. 输出图中两点间的全部路径

    输出图中两点间的全部路径(可直接测试) 需要提前了解图以及图的存储和遍历的相关知识.回溯递归等要点,以下是具体代码实现 //输出图中一个点到另一个点的所有的路径 #include <iostre ...

  2. python两点之间最短距离_最短路径(图中两点间最短路径)

    packagecom.cn.datastruct;importjava.util.Scanner;//最短路径求解 public classDistMin {static classGraphMatr ...

  3. 用两种遍历方法判断图中两点是否有路径

    用两种遍历方法判断图中两点是否有路径(可直接测试) 邻接表.图.图的两种遍历以及图中路径的基本概念,可以去自行了解和学习(下面是代码实践)可直接在自己主机测试 #include <iostrea ...

  4. 江苏省小学升初中数学题:求图中阴影面积

    江苏省小学升初中数学题:求图中阴影面积 分析:小学升初中数学题应该是要考察图形的分割与拼接,而此题中的阴影面积实际最终需要用到三角函数的知识,无法简单通过图形的分割与拼接求得.如果是小学数学题,其真实 ...

  5. java判断图中两点是否连通_连通分量(求有几个连通分量+判断是否两点连通+是否为强联通图 相应例子)...

    参考博客: https://blog.csdn.net/jinzk123/article/details/52231527 https://blog.csdn.net/qq_40998706/arti ...

  6. 图 矩阵 两点间有m的路径 矩阵乘法_代数图论I: 基本理论和无向图的同调

    本文内容: 1 图的基本概念 2 无向图的同调理论 1 图的基本概念 首先我们来复习一下图的定义: [图] 图是一个对 , 这里 是一个集合,集合的元素叫做 顶点(vertices), 而 的元素是二 ...

  7. 求图中的最大独立集或最大团(UVA 193)

    几个概念 完全图:简单无向图,图中的任意两个点之间有且仅有一条边相连,所有完全图都是它本身的团. 补图:图G的补图通俗的来讲就是完全图Kn去除G的边集后得到的图Kn-G. 团(clique):顶点集C ...

  8. 学校的校园景点平面图(校园景点迷你地图C++数据结构)(查询图中顶点间的最短路径查询图中任意两个顶点间的所有路径)

    学校的校园景点平面图(校园景点迷你地图C++&数据结构) 设计要求: (1)建图 以图中顶点表示主要景点,并存放景点的编号.名称.简介等信息: (2)查询 该系统可以查询景点的信息: 查询图中 ...

  9. 求有向图中两点最短距离java_Java 迪杰斯特拉算法实现查找最短距离

    迪杰斯特拉算法 迪杰斯特拉算法是由荷兰计算机科学家狄克斯特拉于1959 年提出的,因此又叫狄克斯特拉算法.是从一个顶点到其余各顶点的最短路径算法,解决的是有向图中最短路径问题.迪杰斯特拉算法主要特点是 ...

最新文章

  1. 【Java 并发编程】线程锁机制 ( 锁的四种状态 | 无锁状态 | 偏向锁 | 轻量级锁 | 重量级锁 | 锁竞争 | 锁升级 )
  2. vue饼图组件_vue2.0 自定义 饼状图 (Echarts)组件
  3. iOS显示性能优化过程讲解
  4. 数列极差(信息学奥赛一本通-T1427)
  5. 解决layui laydate动态创建多个时不起作用点击无效的问题
  6. Python简记--函数
  7. cisco 华三 对接_Cisco ACS 5.6与华为,H3C设备对接操作指引
  8. 【redis】mac安装redis
  9. VB 文件编码互换模块(支持 Ansi,UTF-8,Unicode(little endian),Unicode big endian)
  10. ecshop getRow getAll getOne 返回值的区别
  11. neutron用linux_bridge部署provider网络
  12. JavaScript基础专题之执行上下文和执行栈(二)
  13. 西门子s7-200plc下载线驱动
  14. C++变量前面加下划线的含义
  15. 英语四六级考试技巧/英语四六级真题
  16. 台式计算机那里可以录音,录音机怎么录音?电脑录音介绍
  17. 三方支付之支付宝支付实现逻辑
  18. python研究背景与意义_研究背景与意义
  19. Logback 学习笔记
  20. Python 3 字符串 strip( ) 方法

热门文章

  1. Monitor:单节点监控之Cadvisor
  2. 用arcgis制作色带图例简明教程
  3. Java宇layUi结合xm-select 实现复选框查询功能
  4. 函数的闭包,闭包的用途
  5. QUI操作超时弹出登录窗口登录的处理方式
  6. 微信小程序——不同角色的导航栏显示不同
  7. 龙芯3A4000处理器解读 ②
  8. java启动参数 -xmn_Java 进阶 (三) JVM参数说明
  9. 问题排查_服务调用失败
  10. pwm 正弦波_CC6420 低噪声,高效率,5V/12V 450mA 单相正弦波直流无刷马达驱动