#include<iostream>
#include<cstring>
using namespace std;
int m,n;// m为结点个数 n为边数
int d[105][105],f[105];
bool vis[105];
int pre[105];// pre数组来记录最短路径
void dijkstra(int s) {
memset(f,0x3f,sizeof(f));
// f数组来存储每一个点到源点s的最短路径长度
// 最开始的时候任意一个点到源点都设为无穷大即0x3f3f3f3f
f[s]=0;// 最开始源点到自身的最短路径肯定是0
for(int i=0;i<m;i++) {
int u=-1,Min=0x3f3f3f3f;
// 定义一个u来记录从当前点开始到源点路径最短的一个点
// 然后使用这个点来更新其他点,Min用来记录到底是哪个点最优也就是到源点最短
for(int j=0;j<m;j++) {// 遍历每一个点来找这个最优点
if(vis[j]==false&&f[j]<Min) {
u = j;// vis数组记录当前点是否已经访问过
// 我们需要一个还没有访问过的点,也就是vis为false的点
// 如果这个点比Min还要小的话就记录下来
Min = f[j];// 同时记录下当前最优点的值
}
}
if(u==-1) return;
// 如果遍历了所有点,没有一个符合最优点的条件则可以返回
vis[u]=true;
// 我们接下来访问u这个结点,所以要把u的vis设为true
// 下面的步骤是利用u这个中转点更新其他点到源点s的最短路径值
for(int j=0;j<m;j++) {// 遍历所有点看是否能更新到源点的最短路径
if(vis[j]==false&&d[u][j]!=0x3f3f3f3f&&f[u]+d[u][j]<f[j]) {
// 第一个条件为什么要更新点的vis为false也就是没有遍历过
// 因为我们每次遍历的点已经到源点是最短路径了,所以不需要重复更新
// 第二个条件d[u][j]为什么不能等于0x3f3f3f3f也就是说
// 我们u到j这两个点之间需要有路径才能更新到源点的最短路径
// 第三个条件也就是说我们当前更新的这个点j如果经过u这个中转点
// 再到源点s路径要小于原来的路径长度,那么我们就可以更新,d[u][j]是u到j的路径长度
f[j] = f[u]+d[u][j];// 更新点j到源点s的最短路径
pre[j] = u; // 把j的前驱点设为u,因为我们是从u到j的
}
}
}
}
void findPath(int s,int v) {
// 寻找路径我们使用递归算法来寻找路径
if(s==v) {// 如果s已经等于v了 说明我们已经从v倒序找到s了
cout<<s<<" ";
return;// 然后就可以从源点s开始输出路径
} // 如果s不等于v,也就是说当前路径还没有找到s
findPath(s,pre[v]);// 递归找s和v的前驱pre[v]
cout<<v<<" ";// 路径从前往后输出,所以先找到pre[v]之后再输出当前的v
}
int main() {
cin>>m>>n;
int x,y,z;
memset(d,0x3f,sizeof(d)); // 最开始将任意两个节点之间的边
// 都设为0x3f3f3f3f(一亿多的一个16进制数) 相当于无穷大
for(int i=0;i<m;i++) {
d[i][i]=0;// 自身到自身为0
}
for(int i=1;i<=n;i++) {
cin>>x>>y>>z;// 起始点 终止点 边的权值
d[x][y]=z;// 有向图只需要建立从x到y的一条边
// 如果是无向图多写一句 d[y][x]=z;表明从y到x也有一条权值为z的边
}
int s,v;//v是我们要求的最终点
cin>>s>>v;// s为源点也就是找最短路径的起始点
dijkstra(s);// 从s源点开始迪杰斯特拉算法
cout<<f[v]<<'\n';
findPath(s,v);// 寻找从起始点s到终止点v的路径
return 0;
}
矿大数据结构实验 迪杰斯特拉求最短路径并求出路径
最新推荐文章于 2023-06-06 21:30:10 发布