Dijkstra算法(《算法笔记》)
一、算法思想
Dijkstra算法适用于单源最短路问题,即给定图G和起点s,通过算法得到从s到其他每个顶点的最短距离。
基本思想:设置一个集合S,存放已经被访问过的点,每次从V-S(未被访问过的点)中选择与起点s距离最短的点(记为u),访问并加入集合S中。将u作为中介点,优化所有从s经过u到达v的最短距离。
二、具体实现
-
集合S(存放已经被访问过的点)用bool型数组 vis[]实现,vis中的元素初始化都为false,被访问过后变为true
-
用int型数组表示从起点s到v的最短距离,初始化赋为一个很大的数INF(1000000000)
-
图用邻接矩阵表示,int型的数组G[][],两个点不可达,则G[u][v]为INF,两个点可达,则为它们之间的距离
伪代码实现:
Dijkstra(G,dis[],s){
初始化;
for(循环n次){
u= 还未被访问中使dis[u]最小的点的下标;
访问u;
for(从u可以到达的所有顶点v){
if(v未被访问&&以u为中介点可以使dis[v]更小)
优化dis[v]
}
}
}
三、代码实现
C++版本
#include<iostream>
#include<stdio.h>
#include<algorithm>
using namespace std;
const int MAXN=1000; //最大顶点数
const int INF=1000000000; //无穷大的距离值
int n; //顶点数
int G[MAXN][MAXN]; //图的邻接矩阵
bool vis[MAXN]={false}; //没访问过的顶点为false
int dis[MAXN];
void Dijkstra(int s){ //给定一个起点,计算到每个点距离的最小值
fill(dis,dis+MAXN,INF); //将距离的每一个值赋值为INF
dis[s]=0; //到自身的距离为0
int u; //未被访问的顶点的集合中与s距离最小的点
int minv; //最小距离
for(int i=0;i<n;i++){ //每次选择一个未被访问的顶点中距离最小的点
u=-1;
minv=INF;
for(int j=0;j<n;j++){
if(vis[j]==false && dis[j]<minv){
u=j;
minv=dis[j];
}
}
if(u==-1) //剩下未被访问的顶点与s不连通
return;
else{
vis[u]=true; //访问u
//如果v未被访问过,u可达v,已u为中介可以使dis[v]更优就更新dis[v]
for(int v=0;v<n;v++){
if(vis[v]==false&&G[u][v]!=INF&&((dis[u]+G[u][v])<dis[v])){
dis[v]=dis[u]+G[u][v]; //更新dis[v]
}
}
}
}
}
int main()
{
int u,v,w;
int m,s;
fill(G[0],G[0]+MAXN*MAXN,INF);
printf("输入顶点数和边数和起点:");
scanf("%d%d%d",&n,&m,&s);
for(int i=0;i<m;i++){
scanf("%d%d%d",&u,&v,&w);
G[u][v]=w;
}
Dijkstra(s);
for(int i=0;i<6;i++){
printf("%d ",dis[i]);
}
return 0;
}
Python版本
MAXN = 1000 # 最大顶点数
INF = 1e9 # 无穷大的值
G = [[INF]*MAXN for i in range(MAXN)] # 图的邻接矩阵
dis = [INF]*MAXN # 每一个点与起点距离的最小值
vis = [False]*MAXN # 存放已经被访问过的点
n=int(input()) # 输入顶点数
def Dijkstra(s):
dis[s] = 0
for i in range(n): # 循环n次
minv = INF
u = -1
for j in range(n): # 寻找与s距离最小的点,并且该点未被访问过
if vis[j] == False and dis[j]<minv:
u = j
minv = dis[j]
if u== -1:
return
else:
vis[u] = True
for v in range(n): # 以u为中介点,优化从s经过u到达v的最短路径
if vis[v]==False and G[u][v]!=INF and dis[u] + G[u][v] < dis[v]:
dis[v] = dis[u] + G[u][v]
四、题目
有的题目会有多条达到最短距离的路径,就要看第二标尺,来确定最终选择哪条路径
- 给每条边增加一个边权,要求在最短路径上的边权之和最小
- 给每个点增加一个点权,要求在最短路径上的点权之和最大
- 问有多少条路径