//http://ac.jobdu.com/problem.php?cid=1040&pid=75
//主要掌握弗洛伊德算法,三重循环,理解记忆
#include <stdio.h>
int ans[101][101]; //初始值是该图的邻接矩阵
int main()
{
int n,m,i,j,k;
while (scanf("%d%d",&n,&m)!=EOF &&(n!=0 &&m !=0))
{
for (i=1;i<=n;i++)
{
for (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 (k=1;k<=n;k++) //k循环到n,允许经过的中间节点编号<=k
{
for (i=1;i<=n;i++)
{
for (j=1;j<=n;j++)
{
if (ans[i][k]==-1 || ans[k][j]==-1) //i到k或k到j有一个不通,保持原值
{
continue;
}
if (ans[i][j]==-1 || ans[i][k]+ans[k][j]<ans[i][j])
{//i到j不可达,或经过k路径变短.前提就是i到k且k到j通
ans[i][j]=ans[i][k]+ans[k][j];
}
}
}
}
printf("%d\n",ans[1][n]);
}
return 0;
}
/*
对于上机测试,结点树不能大于200
若两点间有多条边时,选择最小的边赋给邻接矩阵
若图用邻接表存储,转换为邻接矩阵
算法得到所有节点间的最短路径,适用于求多对节点间的最短路径
*/
使用dijkstra算法
#include <stdio.h>
#include <vector>
using namespace std;
struct E //邻接表中链表元素结构体(边)
{
int next; //直接相邻节点
int c; //该边权值
};
vector <E> edge[101]; //vector作邻接链表,结点不超过100
bool mark[101]; //mark[i]为true时,表示结点i的最短路径长度已经得到,结点i加入集合k
int dis[101]; //mark[i]=true时,从1到i的最短路径长度
//mark[i]=false时,从1到k中某点的最短路径长度再加上从该点到i的距离
int main()
{
int n,m,i,j;
while (scanf("%d%d",&n,&m)!=EOF && n!=0 &&m!=0)
{
for (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); //将该边加入结点a的边表,作为邻接边
tmp.next=a;
edge[b].push_back(tmp); //加入结点b的边表(因为无向图所以加两次)
}
for (i=1;i<=n;i++) //初始化
{
dis[i]=-1; //-1表示不可达
mark[i]=false; //所有节点不属于集合k
}
dis[1]=0;
mark[1]=true; //1到1最近,长度为0,1加入结合k
int newP=1; //集合k中新加入的点为结点1
for (i=1;i<n;i++) // 循环n-1次,按路径递增顺序确定其他点的最短路径
{
for (j=0;j<edge[newP].size();j++) //遍历新加入k的结点的直接相邻边
{
int t=edge[newP][j].next; //该边的另一节点
int c=edge[newP][j].c;
if (mark[t]==true) //另一节点也属于k,跳过
{
continue;
}
if (dis[t]==-1 || dis[t]>dis[newP]+c) //该节点尚不可达或有更短路径
{
dis[t]=dis[newP]+c;
}
}
int min=123123123; //最小值初始化为一个大数
for (j=1;j<=n;j++) //遍历所有节点
{
if (mark[j]==true) //若其属于结合k,跳过
{
continue;
}
if (dis[j]==-1) //若该节点仍不可达(肯定不最短),跳过
{
continue;
}
if (dis[j]<min) //依次比较找最短
{
min=dis[j]; //暂时保存最短
newP=j; //暂时保存newP最短边的另一结点
}
}
mark[newP]=true; // 该点加入集合k,dis[newP]表示从1到newP的最短距离
}
printf("%d\n",dis[n]);
}
return 0;
}
/*
mark[i]=true时,结点i属于集合k,dis[i]表示从1到i的最短路径长度
mark[i]=false时,结点i不属于集合k,dis[i]表示从1到k中某点的最短路径长度再加上从该点到i的最短距离
想想一个有向图的求解最短路径的做法,先初始化,再将源点加入,更新相邻边,找到最短
更新newP,再找相邻边,再找其最短,更新newP。。。
*/