/*
Dijkstra算法:
1.将所有的顶点分为两部分: 已知最短路程的顶点集合P和 未知最短路径的顶点集合Q。
最开始,已知最短路径的定点集合P中只有源点一个顶点。用 visit数组记录哪些顶点在P中。
对于某个顶点i,如果 visit[i]为1则表示此顶点在P中,若visit[i]为0,则表示此顶点在集合Q中
2.设置源点v到自己的最短路径为0,即 dis[v]=0。若存在源点能直接到达的顶点i,则把 dis[i]设为e[v][i]
同时把所有其他(源点不能直接到达的)顶点的最短路径设为 inf(无穷大)
3.在集合Q中所有的顶点中选择一个 离源点v最近的顶点u(即 dis[u]最小), 加入到集合P。
并考察所有以u为起点的边,对每一条边进行 松弛操作。
如果存在一条从u到s的边,可以通过将边u->s添加到尾部来拓展一条从v到s的路径,这条路径的长度是 dis[u]+e[u][s].
如果这个值比目前已知的dis[s]的值要小,则可以用新值来替代当前dis[s]中的值。
4.重复第3步,直到集合Q为空,算法结束。最终dis数组中的值就是源点到所有顶点的完整路径。
Dijkstra算法:
1.将所有的顶点分为两部分: 已知最短路程的顶点集合P和 未知最短路径的顶点集合Q。
最开始,已知最短路径的定点集合P中只有源点一个顶点。用 visit数组记录哪些顶点在P中。
对于某个顶点i,如果 visit[i]为1则表示此顶点在P中,若visit[i]为0,则表示此顶点在集合Q中
2.设置源点v到自己的最短路径为0,即 dis[v]=0。若存在源点能直接到达的顶点i,则把 dis[i]设为e[v][i]
同时把所有其他(源点不能直接到达的)顶点的最短路径设为 inf(无穷大)
3.在集合Q中所有的顶点中选择一个 离源点v最近的顶点u(即 dis[u]最小), 加入到集合P。
并考察所有以u为起点的边,对每一条边进行 松弛操作。
如果存在一条从u到s的边,可以通过将边u->s添加到尾部来拓展一条从v到s的路径,这条路径的长度是 dis[u]+e[u][s].
如果这个值比目前已知的dis[s]的值要小,则可以用新值来替代当前dis[s]中的值。
4.重复第3步,直到集合Q为空,算法结束。最终dis数组中的值就是源点到所有顶点的完整路径。
*/
#include<iostream>
#define maxnum 100
#define inf 999999
using namespace std;
void Dijkstra(int n,int v,int *dis,int *prev,int c[maxnum][maxnum]){
bool visit[maxnum]; //判断该点是否已经存入集合S中
//初始化
for(int i=1;i<=n;i++){
dis[i]=c[v][i];
visit[i]=0; //初始都未使用过该点
if(dis[i]==inf)
prev[i]=0;
else
prev[i]=v;
}
dis[v]=0;
visit[v]=1;
for(int i=2;i<=n;i++){
int min=inf;
int u=v;
//找出当前未使用点j的dis[j]最小值
for(int j=1;j<=n;j++)
if(!visit[j]&&dis[j]<min){
u=j; //u保存当前邻接点中距离最小点的标号
min=dis[j];
}
visit[u]=1; //表示u点已经存入集合P中
//更新dis
for(int j=1;j<=n;j++)
if(!visit[j]&&c[u][j]<inf){
if(dis[u]+c[u][j]<dis[j]){//松弛操作
dis[j]=dis[u]+c[u][j];
prev[j]=u;
}
}
}
}
void showPath(int *prev,int v,int u){
int que[maxnum];
int tot=1;
que[tot]=u;
tot++;
int tmp=prev[u];
while(tmp!=v){
que[tot]=tmp;
tot++;
tmp=prev[tmp];
}
que[tot]=v;
for(int i=tot;i>=1;i--){
if(i!=1)
cout<<que[i]<<"->";
else
cout<<que[i]<<endl;
}
}
int main(){
freopen("input1.txt","r",stdin);
int dis[maxnum];
int prev[maxnum];
int c[maxnum][maxnum];
int n,m;
cin>>n;
cin>>m;
int p,q,w;
for(int i=1;i<=n;i++)
for(int j=1;j<=n;j++)
c[i][j]=inf;
for(int i=1;i<=m;i++){
cin>>p>>q>>w;
if(w<c[p][q]){
c[p][q]=w;
c[q][p]=w;
}
}
for(int i=1;i<=n;i++)
dis[i]=inf;
for(int i=1;i<=n;i++){
for(int j=1;j<=n;j++)
printf("%8d",c[i][j]);
printf("\n");
}
Dijkstra(n,1,dis,prev,c);
//最短路径长度
cout << "源点到最后一个顶点的最短路径长度: " << dis[n] << endl;
//路径
cout << "源点到最后一个顶点的路径为: ";
showPath(prev,1,n);
}