迪杰斯特拉算法可以确定特定节点到其他所有节点的最短路径。
不妨有节点1到N,求从节点1出发到所有节点的最短路径。
按照最短路径递增的顺序求解。
类似prim算法,维持一个已经确定了最短路径的节点集合K,K外的节点最短路径暂时未知。
问题一般化,K里面有已经保存了从1出发到达的最短路径的节点p1, p2, ..., pm。
那么,第m+1近的节点的最短路径必然包含两个部分:
从1出发到K里面的某个节点p2;
再由p2经过一条边(u, v, c)到达,u属于集合K,v在K外。
2 1
1 2 3
3 3
1 2 5
2 3 5
3 1 2
0 0
Sample Output
3
2
C++代码:
#include<bits/stdc++.h>
using namespace std;
const int INF=0x3f;
const int maxn=105;
int n, m;
int dis[maxn];
int vis[maxn];
int g[maxn][maxn];
void dijkstra(){
memset(vis, 0, sizeof(vis));//初始化是否加入集合K的标志
for(int i=1; i<=n; i++) dis[i]=g[1][i];//初始化从1开始的距离
vis[1]=1;//节点1加入集合K
dis[1]=0;
int next;
for(int i=2; i<=n; i++){//遍历寻找下一个节点,dis最小
int mini=INF;
for(int j=1; j<=n; j++){
if(!vis[j] && dis[j]<mini){//寻找最小的dis
mini=dis[j];
next=j;
}
}
vis[next]=1;//打上集合K的标记
for(int j=1; j<=n; j++){//看看经过next节点是否可以更新节点的最短距离
if(!vis[j] && dis[next]+g[next][j]<dis[j])
dis[j]=dis[next]+g[next][j];
}
}
}
int main(){
while(cin>>n>>m && n!=0 && m!=0){
memset(g, 0x3f, sizeof(g));//每幅图初始化边
while(m--){//读入m条边
int a, b, c;
cin>>a>>b>>c;
g[a][b]=g[b][a]=c;
}
dijkstra();
cout<<dis[n]<<endl;
}
return 0;
}
python代码:
import sys
INF=0x3f
maxn=105
def dijkstra(n):
for i in range(1, n+1): #从节点1出发
dis[i]=g[1][i]
dis[1]=0 #节点1加入K
vis[1]=True #打上标记
next=1 #下一个即将加入的,1只是用来初始化
for i in range(2, n+1):# 1已经加入K,从2开始
mini=INF
for j in range(1, n+1):# 寻找最短距离的next
if vis[j]==False and dis[j]<mini:
mini=dis[j]
next=j
vis[next]=True #打上集合K的标记
for j in range(1, n+1): #是否可以经过next更新其他节点的距离
if vis[j]==False and dis[next]+g[next][j]<dis[j]:
dis[j]=dis[next]+g[next][j]
while True:
n, m=map(int, input().split()) #n个节点 m条边
if n!=0 and m!=0: #有效图
g = [[INF]*maxn for i in range(maxn)] #图的初始化
dis = [INF]*maxn
vis = [False]*maxn
while m: #读取m条边
a,b,c=map(int, input().split())
g[a][b]=c
g[b][a]=c
m -= 1
dijkstra(n)
print(dis[n])
else:
sys.exit()