问题 A: 算法7-15:迪杰斯特拉最短路径算法
[命题人 : 外部导入]
时间限制 : 1.000 sec 内存限制 : 32 MB
题目描述
在带权有向图G中,给定一个源点v,求从v到G中的其余各顶点的最短路径问题,叫做单源点的最短路径问题。
在常用的单源点最短路径算法中,迪杰斯特拉算法是最为常用的一种,是一种按照路径长度递增的次序产生最短路径的算法。
可将迪杰斯特拉算法描述如下:
在本题中,读入一个有向图的带权邻接矩阵(即数组表示),建立有向图并按照以上描述中的算法求出源点至每一个其它顶点的最短路径长度。
输入
输入的第一行包含2个正整数n和s,表示图中共有n个顶点,且源点为s。其中n不超过50,s小于n。
以后的n行中每行有n个用空格隔开的整数。对于第i行的第j个整数,如果大于0,则表示第i个顶点有指向第j个顶点的有向边,且权值为对应的整数值;如果这个整数为0,则表示没有i指向j的有向边。当i和j相等的时候,保证对应的整数为0。
输出
只有一行,共有n-1个整数,表示源点至其它每一个顶点的最短路径长度。如果不存在从源点至相应顶点的路径,输出-1。
请注意行尾输出换行。
样例输入 Copy
4 1 0 3 0 1 0 0 4 0 2 0 0 0 0 0 1 0
样例输出 Copy
6 4 7
提示
在本题中,需要按照题目描述中的算法完成迪杰斯特拉算法,并在计算最短路径的过程中将每个顶点是否可达记录下来,直到求出每个可达顶点的最短路径之后,算法才能够结束。
迪杰斯特拉算法的特点是按照路径长度递增的顺序,依次添加下一条长度最短的边,从而不断构造出相应顶点的最短路径。
另外需要注意的是,在本题中为了更方便的表示顶点间的不可达状态,可以使用一个十分大的值作为标记。
#include<bits/stdc++.h>
using namespace std;
const int nmax=100,INF=100000000;
bool collected[nmax];
int dist[nmax];
int cnt;
int n,s,temp;
int a[55][55];
void Dijkstra(int s)
{
fill(dist,dist+nmax,INF);//初始化源点到每个结点的距离dist,
fill(collected,collected+nmax,false);//收录标记collected;
dist[s]=0;//到源点本身距离为0;
int w,mi;
for(int i=0; i<n; i++)
{
mi=INF;
for(int j=0; j<n; j++)//每次找到最短的点w;
{
if(!collected[j]&&dist[j]<mi)//未收录过的,距离正常的且最小的节点;
{
mi=dist[j];
w=j;
//printf("j=%d\n",j);
}
}
collected[w]=true;//收录w点;后续以该点为中转;
//printf("get V=%d\n",w);
for(int j=0; j<n; j++)
{
if(!collected[j]&&a[w][j]<INF) //源点到j的距离大于到w加上w到j的距离,则更新dist[j]
{
dist[j]=min(dist[j],dist[w]+a[w][j]);
}
}
}
}
int main()
{
cin>>n>>s;
for (int i = 0; i < n; i++)
{
for (int j = 0; j < n; j++)
{
scanf("%d", &a[i][j]);
if (i != j && !a[i][j])
a[i][j] = INF;
}
}
Dijkstra(s);
for(int i=0; i<n; i++)
{
if(i!=s)
{
if(dist[i]<INF)
printf("%d ",dist[i]);
else
printf("-1 ");
}
}
printf("\n");
return 0;
}