// 弗洛伊德算法:求两点间的最短路径
// 特点:时间复杂度为O(n^3),结点不超过200;当两个结点间多出一条边时,选择长度较小的那条边;
// 全源最短路径问题:多个结点对之间的最短路径问题
#include<stdio.h>int ans[101][101];
int main()
{
int n,m;
while(scanf("%d%d",&n,&m)!=EOF){
if(n==0 && m==0) break;
for(int i=1;i<=n;i++){
for(int j=1;j<=n;j++){
ans[i][j]=-1; // 对邻接矩阵初始化,-1表示无穷
}
ans[i][i]=0; // 自己到自己的路径长度为0
}
while(m--){
int a,b,c;
scanf("%d%d%d",&a,&b,&c);
ans[a][b]=ans[b][a]=c; // 无向图
}
for(int k=1;k<=n;k++){ // 依次代表经过的中间结点
for(int i=1;i<=n;i++){
for(int j=1;j<=n;j++){
if(ans[i][k]==-1 || ans[k][j]==-1) continue;
// 若两值有一个为无穷,则不能经过k结点
if(ans[i][j]==-1 || ans[i][j]>ans[i][k]+ans[k][j])
ans[i][j]=ans[i][k]+ans[k][j];
}
}
}
printf("%d\n",ans[1][n]);
}
return 0;
}
// 迪杰斯特拉算法:求得某特定结点到其他所有结点的最短路径长度
// 特点:时间复杂度为O(n^2),空间复杂度为O(n)
// 单源最短路径问题
#include<stdio.h>
#include<vector>
using namespace std;
struct E{ // 邻接链表中的链表元素结构体
int next; // 代表直接相邻的结点
int c; // 代表该边的权值
};
vector<E> edge[101]; // 邻接链表
bool mark[101]; // 标记,当mark[i]为true时表示结点i的最短路径长度已经得到,该结点已经加入集合k
int Dis[101]; // 距离向量,当mark[i]为true时,表示已得的最短路径长度;
// 否则,表示所有从结点1出发,经过已知的最短路径到达集合k中的某结点,
// 再经过一条边到达节点i的路径最短的距离
int main()
{
int n,m;
while(scanf("%d%d",&n,&m)!=EOF){
if(n==0 && m==0) break;
for(int i=1;i<=n;i++) edge[i].clear(); // 初始化邻接链表
while(m--){
int a,b,c;
scanf("%d%d%d",&a,&b,&c);
E tmp;
tmp.c=c;
tmp.next=b; edge[a].push_back(tmp); // 将邻接信息加入邻接链表,
tmp.next=a; edge[b].push_back(tmp); // 由于原图为无向图,故每条边信息都要添加到其两个顶点的两条单链表中
}
for(int i=1;i<=n;i++){ // 初始化
Dis[i]=-1; // 所有距离为-1,即不可达
mark[i]=false; // 所有结点不属于集合k
}
Dis[1]=0; // 得到最近的点为结点1,长度为0
mark[1]=true; // 将结点1加入集合k
int newP=1; // 集合k中新加入的点为结点1
for(int i=1;i<n;i++){ // 循环n-1次,按照最短路径递增的顺序确定其他n-1个点的最短路径长度
for(int j=0;j<edge[newP].size();j++){ // 遍历与新加入集合k中的结点直接相邻的边
int t=edge[newP][j].next; // 该边的另一个结点
int c=edge[newP][j].c; // 该边的长度
if(mark[t]==true) continue; // 若另一个结点也属于集合k,则跳过
if(Dis[t]==-1 || Dis[t]>Dis[newP]+c) //若该结点尚不可达,或者该结点从新结点经过一条边到达时比以往距离更短
Dis[t]=Dis[newP]+c; // 更新其距离信息
}
int min=123123123; // 最小值初始化为一个大整数,为找最小值做准备
for(int j=1;j<=n;j++){ // 遍历所有结点
if(mark[j]==true) continue; // 若其属于集合k则跳过
if(Dis[j]==-1) continue; // 若该结点仍不可达则跳过
if(Dis[j]<min){ // 若该结点经由结点1至集合k中的某点在经过一条边到达时距离小于当前最小值
min=Dis[j]; // 更新其为最小值
newP=j; // 新加入的点暂定为该结点
}
}
mark[newP]=true; // 将新加入的点加入集合k,Dis[newP]虽然数值不变,但意义发生变化,
// 有所有经过集合k中的结点再经过一条边时的距离中的最小值变为从结点1到结点newP的最短距离
}
printf("%d\n",Dis[n]);
}
return 0;
}