个人理解:这个求单源最短路的方法和Prim算法求最小生成树非常相似,都是从未加入顶点
中找出一个顶点权值最小的,然后加进顶点集当中,唯一不同的是Prim更新的是新加入点与
其他点的最小权值,而Dijkstra是更新源点到该点总权值(或者说是进行一轮松弛)。
再次copy下维基百科:
算法描述
这个算法是通过为每个顶点 v 保留目前为止所找到的从s到v的最短路径来工作的。初始时,原点 s 的路径长度值被赋为 0 (d[s] = 0),若存在能直接到达的边(s,m),则把d[m]设为w(s,m),同时把所有其他(s不能直接到达的)顶点的路径长度设为无穷大,即表示我们不知道任何通向这些顶点的路径(对于 V 中所有顶点 v除 s 和上述 m 外 d[v] = ∞)。当算法退出时,d[v] 中存储的便是从 s 到 v 的最短路径,或者如果路径不存在的话是无穷大。 Dijkstra 算法的基础操作是边的拓展:如果存在一条从 u 到 v 的边,那么从 s 到 v 的最短路径可以通过将边(u, v)添加到尾部来拓展一条从 s 到 u 的路径。这条路径的长度是 d[u] + w(u, v)。如果这个值比目前已知的 d[v] 的值要小,我们可以用新值来替代当前 d[v] 中的值。拓展边的操作一直运行到所有的 d[v] 都代表从 s 到 v 最短路径的花费。这个算法经过组织因而当 d[u] 达到它最终的值的时候每条边(u, v)都只被拓展一次。
HDU 2544可以用来测试代码正确与否;
#include<stdio.h>
#include<string.h>
int graph[110][110],dis[110];
const int inf=0xfffff;
void initi(int n)
{
for(int i=1;i<=n;i++)
for(int j=1;j<=n;j++)
graph[i][j]=inf;
for(int i=1;i<=n;i++)
dis[i]=inf;
dis[1]=0;
}
void Dijkstra(int n)
{
int minLoc,i,j,vis[110];
memset(vis,0,sizeof(vis));
vis[1]=1;
for(i=2;i<=n;i++)
dis[i]=graph[1][i];
for(i=2;i<=n;i++)
{
int min=inf;
for(j=2;j<=n;j++)
{
if(!vis[j]&&dis[j]<min)//寻找未加入顶点中与已加入顶点中的最小总权值
{
min=dis[j];
minLoc=j;
}
}
vis[minLoc]=1;
for(j=2;j<=n;j++)//对新加入顶点进行一轮松弛
if(!vis[j]&&dis[minLoc]+graph[minLoc][j]<dis[j])
dis[j]=dis[minLoc]+graph[minLoc][j];
}
}
int main()
{
int i,j,n,m;
while(scanf("%d%d",&n,&m))
{
int a,b,c;
if(n==0&&m==0)
break;
initi(n);
for(i=0;i<m;i++)
{
scanf("%d%d%d",&a,&b,&c);
graph[a][b]=graph[b][a]=c;
}
Dijkstra(n);
printf("%d\n",dis[n]);
}
}