首先,按个人理解说一下最小生成树和最短路的区别:
最小生成树是要把所有点都连接起来,计算最小权值,而最短路不需要连接所有点,只需要连接起点和终点,其他不一定都要连接。
Prim算法和Dijkstra算法的区别就在于此。一开始想了很久。
然后,下面介绍一下Dijkstra算法(大家可以对比一下Prim算法,源码相似度很高,容易混):
先引用一张图,说一下Dijkstra算法的具体思想和步骤:
实现源码:
const int maxn = 105;
int T, n, m;
int map[maxn][maxn];//map[i][j]表示从i点到j点的距离
int d[maxn];//d[i]表示从源点到i点的最短距离
bool vis[maxn];//记录该点是否已经访问过
void Dijkstra(int s){//s为源点
MEM1(vis);
vis[s]=1;
for2(i,1,n){//初始化d[i]数组
d[i]=(i==s?0:map[s][i]);
}
for2(i,2,n){
int x,m=inf;
for2(j,1,n){
if(!vis[j]&&d[j]<m){
m=d[x=j];
}
}
vis[x]=1;
for2(j,1,n){//更新d[i]数组,判断在源点到某点最短路径中插入一点x,从i->x->j的路径是否比i->j短
if(!vis[j])//举例来说,S->D权值为5,而S->B->D权值为3,这是更新S->D的权值,即d[D]=3
d[j]=min(d[j],d[x]+map[x][j]);
}
}
pf(d[n]);//这里可以打印源点s到任意一点的最短路径d[i]
}
int main() {
#ifndef ONLINE_JUDGE
freopen("test.in","r",stdin);
freopen("test.out","w",stdout);
#endif
while(~sfd(n,m)){
if(!n&&!m)
break;
for2(i,1,n){//首先初始化map,主要目的是防止重编的情况
for2(j,1,n){
map[i][j]=i==j?0:inf;
}
}
int a,b,c;
for1(i,0,m){
sft(a,b,c);
if(map[a][b]>c)//更新map[i][k]
map[a][b]=map[b][a]=c;
}
Dijkstra(1);
}
return 0;
}
总的来说,写这篇的文章主要是比较一下Dijkstra和Prim算法的区别,因为之前在学习最小生成树的时候也有看到有些题目最后问的是最短路径,有点疑问。
其实Dijkstra算法个人感觉是Floyd算法的优化,当然Dijkstra算法也可以继续优化,用pair或者优先队列,这里暂不做讨论。