題目描述
第一行兩個整數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