题目描述
第一行两个整数n m。n表示顶点个数(顶点编号为1~n),m表示边的条数。接下来m行表示,每行有3个数x y z。表示顶点x到顶点y边的权值为z。求源点为1的最短路径。
题目来源【坐在马桶上看算法】算法7:Dijkstra最短路算法
题目思路
这道题我只是想练练dijkstra模板,dijkstra主要由两个步骤组成:
- 找到顶点 i 周围距离最近的点 u
- 将u 加入集合(已确定最短路径的点的集合)
- 利用u更新其他所有的点到源点的最短路径距离
代码
#include <iostream>
#include <stdio.h>
using namespace std;
#define inf 0x3f3f3f3f
#define max 100
//edge[i][j]记录i到j的边长,dis[i]记录到i的最短路径长,
//mask[i]记录i点是否加入集合,pre[i]记录i的最短路径上i的前一个点
int edge[max][max],dis[max],mask[max],pre[max];
int main() {
freopen("in.txt","r",stdin);
int n,m;
cin>>n>>m;
//初始化edge[][],默认点到自己的边长为0,其他的默认为inf,即不可达
for(int i=1;i<=n;i++){
for(int j=1;j<=n;j++){
if(i==j) {
edge[i][j]=0;
}
else {
edge[i][j]=inf;
}
}
}
//输入边长
int a,b,w;
for(int i=1;i<=m;i++){
cin>>a>>b>>w;
edge[a][b]=w;
}
//源点为1,所以看1周围的点(没有和1相邻的点距离会是inf)
for(int i=1;i<=n;i++){
dis[i]=edge[1][i];//在这里用边去初始化距离
mask[i]=0;
pre[i]=1;
}
mask[1]=1;//1为源点,让1被访问过
//dijkstra核心操作如下
for(int i=1;i<=n-1;i++){
int min=inf;
int u;
//每一次选出和i最近的点u,加入集合(每次只选一个)
for(int j=1;j<=n;j++){
if(mask[j]==0&&min>dis[j]){
min=dis[j];
u=j;
}
}
//u加入集合
mask[u]=1;
//根据u去更新其他点到源点的距离,因为可能经过u中转之后有的点和源点会更近(所以遍历所有点)
for(int v=1;v<=n;v++){
if(dis[v]>dis[u]+edge[u][v]){
dis[v] = dis[u]+edge[u][v];
pre[v]=u;//以u为中转的话,v到源点的最短路径上v的前一个点就是u
}
}
}
//输出最短路径长度结果
for(int i=1;i<=n;i++){
cout<<dis[i]<<" ";
}
cout<<endl;
//输出最短路径
for(int i=1;i<=n;i++){
int nn=i;
while(nn!=1){
cout<<nn<<"-";
nn=pre[nn];
}
cout<<"1"<<endl;
}
fclose(stdin);
return 0;
}
输入:
6 9
1 2 1
1 3 12
2 3 9
2 4 3
3 5 5
4 3 4
4 5 13
4 6 15
5 6 4
输出:
0 1 8 4 13 17
1
2-1
3-4-2-1
4-2-1
5-3-4-2-1
6-5-3-4-2-1