图(最短路径)1

来源:互联网 发布:反监听软件 编辑:程序博客网 时间:2024/06/11 22:51
/*
题目1447:最短路
题目描述:
在每年的校赛里,所有进入决赛的同学都会获得一件很漂亮的t-shirt。但是每当我们的工作人员把上百件的衣服从商店运回到赛场的时候,却是非常累的!所以现在他们想要寻找最短的从商店到赛场的路线,你可以帮助他们吗?
输入:
输入包括多组数据。每组数据第一行是两个整数N、M(N<=100,M<=10000),N表示成都的大街上有几个路口,标号为1的路口是商店所在地,标号为N的路口是赛场所在地,M则表示在成都有几条路。N=M=0表示输入结束。接下来M行,每行包括3个整数A,B,C(1<=A,B<=N,1<=C<=1000),表示在路口A与路口B之间有一条路,我们的工作人员需要C分钟的时间走过这条路。输入保证至少存在1条商店到赛场的路线。
当输入为两个0时,输入结束。
输出:
对于每组输入,输出一行,表示工作人员从商店走到赛场的最短时间。
样例输入:
2 1
1 2 3
3 3
1 2 5
2 3 5
3 1 2
0 0
样例输出:
3
2
*/
// floyd 时间复杂度 o(n^3) 空间复杂度o(n^2),n为结点个数
// floyd适用于图的结点数<=200个,原图需要转换为邻接矩阵表示
// 两个结点间有多条边时,选择长度最小的边,适用于全源最短路径
#include <stdio.h>
int ans[101][101];//二维数组,其初始值即为该图的邻接矩阵
int main(){
int n,m,i,j,k;
while(scanf("%d%d",&n,&m) != EOF){
if(n==0 && m==0) break;
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从1到N循环,依次代表允许经过的中间结点编号小于等于k
for(i=1;i<=n;i++){
for(j=1;j<=n;j++){//遍历所有ans[i][j],判断其值保持原值还是将要被更新
if(ans[i][k] == -1 || ans[k][j] == -1) continue;
//若两值中有一个值为无穷,则ans[i][j]不能由于经过结点k而被更新,跳过循环,保持原值
if(ans[i][j] == -1 || ans[i][k]+ans[k][j]<ans[i][j])
ans[i][j]=ans[i][k]+ans[k][j];
//当由于经过k可以获得更短的最短路径时,更新该值
}
}

}
printf("%d\n",ans[1][n]);
}


return 0;

}

//dijkstra

#include <stdio.h>
#include <vector>
using namespace std;
struct E{//邻接链表中的链表元素结构体
int next;//代表直接相邻的结点
int c;//代表该边的权值(长度)
};
vector<E> edge[101];//邻接链表
bool mark[101];//标记,当mark[j]为true时表示结点j的最短路径长度已经得到,该
//结点已经加入集合K
int dis[101];//距离向量,当mark[i]为true时,表示已得的最短路径长度;否则,表示
//所有从结点1出发,经过已知的最短路径达到集合K中的某结点,再经过一条边到达结点
//i的路径中最短的距离
int main(){
int n,m,i,j;
while(scanf("%d%d",&n,&m) != EOF){
if(n==0 && m==0) break;
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);
tmp.next = a;
edge[b].push_back(tmp);//将邻接信息加入邻接链表,由于原图为无向图,
//固每条边信息都要添加到其两个顶点的两条单链表中
}
for(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(i=1;i<n;i++){//循环n-1次,按照最短路径递增的顺序确定其他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) continue;//若另一个结点也属于集合K,则跳过
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) 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;
}

0 0