题目描述
在带权有向图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。
请注意行尾输出换行。
样例输入
4 1 0 3 0 1 0 0 4 0 2 0 0 0 0 0 1 0
样例输出
6 4 7
提示
在本题中,需要按照题目描述中的算法完成迪杰斯特拉算法,并在计算最短路径的过程中将每个顶点是否可达记录下来,直到求出每个可达顶点的最短路径之后,算法才能够结束。
迪杰斯特拉算法的特点是按照路径长度递增的顺序,依次添加下一条长度最短的边,从而不断构造出相应顶点的最短路径。
另外需要注意的是,在本题中为了更方便的表示顶点间的不可达状态,可以使用一个十分大的值作为标记。
#include<cstdio>
#include<iostream>
#include<algorithm>
using namespace std;
const int maxn=1010;
const int INF=1000000000;
int n,m,s,G[maxn][maxn]; //n为顶点数,m为边数,s为起点
int d[maxn];
bool vis[maxn]={false};
void Dijkstra(int s){
fill(d,d+maxn,INF);
d[s]=0;
for(int i=0;i<n;i++){
int u=-1,min=INF;
for(int j=0;j<n;j++){
if(vis[j]==false&&d[j]<min){
min=d[j];
u=j;
}
}
if(u==-1) return ;
vis[u]=true;
for(int v=0;v<n;v++){
if(vis[v]==false&&G[u][v]!=INF&&G[u][v]+d[u]<d[v]){
d[v]=G[u][v]+d[u];
}
}
/*
printf("%d\n",u);
for(int k=0;k<n;k++){
printf("%d ",d[k]);
}
printf("\n");*/
}
}
int main(){
scanf("%d%d",&n,&s); //n为顶点数,m为边数,s为起点
//fill(G[0],G[0]+maxn*maxn,INF); //这一句非常重要
for(int row=0;row<n;row++){
for(int col=0;col<n;col++){
scanf("%d",&G[row][col]);
if(G[row][col]==0){
G[row][col]=INF;
}
}
}
Dijkstra(s);
for(int i=0;i<n;i++){
if(i!=s&&i<n-1){
if(d[i]!=INF) printf("%d ",d[i]);
else printf("-1 ");
}
if(i!=s&&i==n-1) {
if(d[i]!=INF) printf("%d\n",d[i]);
else printf("-1\n");
}
}
return 0;
}