变量定义:
mp数组: 存边和边权
vis数组: 标记节点是否已访问
dis数组: 存放起点st到每个点的初始距离
pre数组: 为了方便路径的输出,选择从终点往起点跑,这样用pre数组存放每个节点更新后的前驱节点,以便最后通过链表访问前驱节点的方式,输出起点s到终点t的最短路的路径
算法思路:
Dijkstra: 每次遍历一遍dis数组找的最小值,记录最小值下标k。再通过点k进行松弛操作,遍历点k能够到达的点,若起点通过点k能到达的点u的距离比之前更小,则dis数组,同时更新pre数组,记录u的前驱为k。通过不断的松弛操作,更新dis数组最终求得起点到终点的最短路
//时间复杂度和空间复杂度O(n^2)
#include<iostream>
#include<cstring>
using namespace std;
const int INF=0x3f3f3f3f;
const int maxn=1e3+5;
int n,m,mp[maxn][maxn],dis[maxn],pre[maxn];//pre存前驱节点,用来输出路径
bool vis[maxn];
char s,t;
void Dijkstra(int st){
memset(vis,0,sizeof(vis));//初始化vis
vis[st]=1;
for(int i=1;i<=n;i++){//初始化 dis
dis[i]=mp[st][i];
if(mp[st][i]!=INF)pre[i]=st;
}
for(int i=1;i<=n-1;i++){
int res=INF,k=0;
for(int j=1;j<=n;j++){//找最小边,并记录
if(res>dis[j]&&!vis[j]){
res=dis[j];
k=j;
}
}
vis[k]=1;
for(int j=1;j<=n;j++){//松弛更新 dis
if(dis[j]>dis[k]+mp[k][j]&&!vis[j]){
dis[j]=dis[k]+mp[k][j];//更新dis
pre[j]=k;//更新前驱
}
}
}
}
int main(){
memset(mp,INF,sizeof(mp));//初始化mp
printf("输入顶点数 边数 起点 终点:\n");
cin>>n>>m>>s>>t;
for(int i=1,c;i<=m;i++){
char a,b;
cin>>a>>b>>c;
int x=a-'A'+1,y=b-'A'+1;//字母转数字,从1开始
mp[x][y]=mp[y][x]=c;
}
Dijkstra(t-'A'+1);//从终点往起点跑方便输出路径
printf("%c到%c的最短距离为:%d\n",s,t,dis[s-'A'+1]);
printf("路径为:%c",s);//输出时,数字转字母
int r=s-'A'+1;
while(r!=(t-'A'+1)){//输出路径
printf("->%c",pre[r]+'A'-1);
r=pre[r];
}
return 0;
}
/*
4 4 A D
A D 10
A B 1
B C 2
C D 3
*/
数组存边真的好不爽,调了好久T_T,我还太菜了啊