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]

四、题目

有的题目会有多条达到最短距离的路径,就要看第二标尺,来确定最终选择哪条路径

  1. 给每条边增加一个边权,要求在最短路径上的边权之和最小
  2. 给每个点增加一个点权,要求在最短路径上的点权之和最大
  3. 问有多少条路径
posted @ 2021-05-09 16:13  inss!w!  阅读(435)  评论(0编辑  收藏  举报