最近课上学到Dijkstra算法,老师出了个题,最短路径不唯一时要怎么记录,目前搜到的网上大多Dijkstra算法的代码都只记录了一条最短路径,于是就打算来改进一下,本人学识不多,如有不对的地方,还望指正。
参考代码:最短路:dijkstra算法+路径输出_小鱼yn的博客-CSDN博客_dijkstra算法输出路径
- 思路:这里我使用二维数组path来记录前一个节点,该二维数组的行数和列数相等且等于节点的个数。其中第一行用于记录前一个节点的个数,剩下的每一列用于存储对应节点的前一个节点。初始化的时候给path每个元素赋的值为-1,所以path中没有储存前一个节点的元素的值为-1。
以下为代码:
#include <iostream>
#include <string.h>
#include <stack>
#include<stdio.h>
using namespace std;
#define MAX 100
#define INF 0x3f3f3f3f
#define me(a,b) memset(a,b,sizeof(b))//初始化内存
int dist[MAX],path[MAX][MAX];//储存最短距离和路径
struct MGraph{
int edges[MAX][MAX];//邻接矩阵,记录两点之间的距离,也就是权值
int e,n;//边数和顶点数
}G;
void init(){
memset(G.edges,INF,sizeof(G.edges));
//me(G.edges,(INF));
for(int i=0;i<G.n;i++)
G.edges[i][i]=0;
}
void printf_MG(){
for(int i=0;i<G.n;i++){
for(int j=0;j<G.n;j++){
if(G.edges[i][j]==INF)
printf("inf ");
else
printf("%2d ",G.edges[i][j]);
}
printf("\n");
}
}
void Dijkstra(MGraph g,int u){//u为当前最小指标的点,传入函数时u为起点
int U[MAX],mmin;//分别表示已经遍历过的点、距当前起始点最近的点的距离
//对各数组进行初始化
memset(U,0,sizeof(U));
memset(path,-1,sizeof(path));
//me(dist,INF);
for(int i=0; i<g.n; i++)
{
dist[i]=g.edges[u][i];
if(g.edges[u][i]<INF){//第一次遍历,记录路径--前一个点
path[1][i] =u;//最初u与i之间有边,能直接从u到i,则i点的前一点记为u
path[0][i]=1;
}
}
dist[u]=0;//到本身的距离
for(int i=0; i<g.n; i++) //求出源点到n个点的最短距离
{
mmin=INF;
U[u]=1;//将选出的新的起始点放入U数组中
for(int j=0; j<g.n; j++)
//这个if判断顶点u的加入是否会出现通往顶点j的更短的路径,如果出现,则改变原来路径及其长度,否则什么都不做
{
if(!U[j]&&dist[u]+g.edges[u][j]<dist[j])
{
dist[j]=dist[u]+g.edges[u][j];//更新路径长度
if(path[0][j]==1)
path[1][j]=u;//更新到顶点j的路径
else if(path[0][j]==-1){
path[1][j]=u;
path[0][j]=1;
}
else if(path[0][j]!=1&&path[0][j]!=-1){
for(int k=2;k<=path[0][j];k++){
path[k][j]=-1;
}
path[1][j]=u;
path[0][j]=1;
}
}
if(!U[j]&&dist[u]+g.edges[u][j]==dist[j]){
//判断节点u是否已经在数组里了,避免重复
int judge_exist=0;
for(int w=1;w<G.n;w++){
if(path[w][j]==u){
judge_exist+=1;
}
}
if(judge_exist==0){
path[0][j]+=1;
int num=path[0][j];
path[num][j]=u;
}
}
}
for(int j = 0; j < g.n; j++)
//这个循环每次从剩余顶点中选出一个顶点,通往这个顶点的路径在通往所有剩余顶点的路径中是长度最短的
{
if(U[j] == 0 && dist[j] < mmin)
{
u = j;
mmin = dist[j];
}
}
}
}
void printf_path(){
printf("following is the number of previous nodes corresponding to the shortest path of each vertex:\n");
for(int i=0;i<G.n;i++){
printf("%2d ",path[0][i]);
}
printf("\nfollowing is previous nodes of each vertex:\n");
for(int j=0;j<G.n;j++){
for(int k=1;k<G.n;k++){
printf("%2d ",path[k][j]);
}
printf("\n");
}
printf("following is the length of the shortest path of each vertex:\n");
for(int w=0;w<G.n;w++){
printf("%2d\n",dist[w]);
}
}
int main()
{
int v1,v2,w;
printf("Please input the number of eadges and vertices:\n");
scanf("%d%d",&G.e,&G.n);//输入边数和顶点数
init();
printf("Please input the vi, vj and weights between them:\n");
for(int i=0; i<G.e; i++)
{
scanf("%d%d%d",&v1,&v2,&w);//顶点用数字表示,从0开始,w为权值
G.edges[v1][v2]=w; //输入时不需要输对角元素(同一个点的如v0和v0),也不需要输入值为无穷的
G.edges[v2][v1]=w;//无向图
}
printf_MG();//输出邻接矩阵
int u;
printf("Please input starting point:\n");
scanf("%d",&u);//输入源点
Dijkstra(G,u);
printf_path();
system("pause");
return 0;
}
这里使用的例子为:
输入为:
20 8
0 1 4
0 3 18
0 4 7
0 5 17
0 6 11
1 2 2
1 4 6
1 6 15
2 3 9
2 4 1
2 5 8
2 7 10
3 4 11
3 5 1
3 7 3
4 5 10
4 6 9
4 7 4
5 7 2
6 7 5
0
运行结果为: