求图中两点间的所有的最短路径
一、理论篇
\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 运行结果如下:
求图中两点间的所有的最短路径相关推荐
- 输出图中两点间的全部路径
输出图中两点间的全部路径(可直接测试) 需要提前了解图以及图的存储和遍历的相关知识.回溯递归等要点,以下是具体代码实现 //输出图中一个点到另一个点的所有的路径 #include <iostre ...
- python两点之间最短距离_最短路径(图中两点间最短路径)
packagecom.cn.datastruct;importjava.util.Scanner;//最短路径求解 public classDistMin {static classGraphMatr ...
- 用两种遍历方法判断图中两点是否有路径
用两种遍历方法判断图中两点是否有路径(可直接测试) 邻接表.图.图的两种遍历以及图中路径的基本概念,可以去自行了解和学习(下面是代码实践)可直接在自己主机测试 #include <iostrea ...
- 江苏省小学升初中数学题:求图中阴影面积
江苏省小学升初中数学题:求图中阴影面积 分析:小学升初中数学题应该是要考察图形的分割与拼接,而此题中的阴影面积实际最终需要用到三角函数的知识,无法简单通过图形的分割与拼接求得.如果是小学数学题,其真实 ...
- java判断图中两点是否连通_连通分量(求有几个连通分量+判断是否两点连通+是否为强联通图 相应例子)...
参考博客: https://blog.csdn.net/jinzk123/article/details/52231527 https://blog.csdn.net/qq_40998706/arti ...
- 图 矩阵 两点间有m的路径 矩阵乘法_代数图论I: 基本理论和无向图的同调
本文内容: 1 图的基本概念 2 无向图的同调理论 1 图的基本概念 首先我们来复习一下图的定义: [图] 图是一个对 , 这里 是一个集合,集合的元素叫做 顶点(vertices), 而 的元素是二 ...
- 求图中的最大独立集或最大团(UVA 193)
几个概念 完全图:简单无向图,图中的任意两个点之间有且仅有一条边相连,所有完全图都是它本身的团. 补图:图G的补图通俗的来讲就是完全图Kn去除G的边集后得到的图Kn-G. 团(clique):顶点集C ...
- 学校的校园景点平面图(校园景点迷你地图C++数据结构)(查询图中顶点间的最短路径查询图中任意两个顶点间的所有路径)
学校的校园景点平面图(校园景点迷你地图C++&数据结构) 设计要求: (1)建图 以图中顶点表示主要景点,并存放景点的编号.名称.简介等信息: (2)查询 该系统可以查询景点的信息: 查询图中 ...
- 求有向图中两点最短距离java_Java 迪杰斯特拉算法实现查找最短距离
迪杰斯特拉算法 迪杰斯特拉算法是由荷兰计算机科学家狄克斯特拉于1959 年提出的,因此又叫狄克斯特拉算法.是从一个顶点到其余各顶点的最短路径算法,解决的是有向图中最短路径问题.迪杰斯特拉算法主要特点是 ...
最新文章
- 【Java 并发编程】线程锁机制 ( 锁的四种状态 | 无锁状态 | 偏向锁 | 轻量级锁 | 重量级锁 | 锁竞争 | 锁升级 )
- vue饼图组件_vue2.0 自定义 饼状图 (Echarts)组件
- iOS显示性能优化过程讲解
- 数列极差(信息学奥赛一本通-T1427)
- 解决layui laydate动态创建多个时不起作用点击无效的问题
- Python简记--函数
- cisco 华三 对接_Cisco ACS 5.6与华为,H3C设备对接操作指引
- 【redis】mac安装redis
- VB 文件编码互换模块(支持 Ansi,UTF-8,Unicode(little endian),Unicode big endian)
- ecshop getRow getAll getOne 返回值的区别
- neutron用linux_bridge部署provider网络
- JavaScript基础专题之执行上下文和执行栈(二)
- 西门子s7-200plc下载线驱动
- C++变量前面加下划线的含义
- 英语四六级考试技巧/英语四六级真题
- 台式计算机那里可以录音,录音机怎么录音?电脑录音介绍
- 三方支付之支付宝支付实现逻辑
- python研究背景与意义_研究背景与意义
- Logback 学习笔记
- Python 3 字符串 strip( ) 方法