一、基本思想
☃️用于解决单源最短路径问题的经典算法。它可以找到图中从一个起始节点到所有其他节点的最短路径。
☔️其核心思想是:
1)维护两个集合:已确定最短路径的节点集合(S)和未确定最短路径的节点集合(U)
2)每次从U中选择距离起点最近的节点,将其加入S
3)更新该节点的所有邻居节点的距离估计
4)重复上述过程直到所有节点都在S中
二、算法步骤
🌺1.初始化:
1)创建距离数组dist[],dist[v]表示从起点到节点v的当前最短距离估计
2)将起点的dist设为0,其他所有节点的dist设为无穷大(∞)
3)创建前驱节点数组prev[],用于记录路径
4)将所有节点放入未处理的集合U中
🌻2.主循环:
1)从U中选择dist值最小的节点u
2)将u从U中移除,加入已处理集合S
3)对于u的每一个邻居节点v:
计算从起点经过u到v的距离alt = dist[u] + weight(u, v)
如果alt < dist[v],则更新dist[v] = alt,prev[v] = u
🌼3.终止条件:
当U为空集时,算法终止
此时
dist[]
中存储的就是从起点到各节点的最短距离
三、典型例题
【问题描述】
在带权有向图G中,给定一个源点v,求从v到G中的其余各顶点的最短路径问题,叫做单源点的最短路径问题。
在常用的单源点最短路径算法中,迪杰斯特拉算法是最为常用的一种,是一种按照路径长度递增的次序产生最短路径的算法。
【输入形式】
输入的第一行包含2个正整数n和s,表示图中共有n个顶点,且源点为s。其中n不超过50,s小于n。
以后的n行中每行有n个用空格隔开的整数。对于第i行的第j个整数,如果大于0,则表示第i个顶点有指向第j个顶点的有向边,且权值为对应的整数值;如果这个整数为0,则表示没有i指向j的有向边。当i和j相等的时候,保证对应的整数为0。
【输出形式】
只有一行,共有n-1个整数,表示源点至其它每一个顶点的最短路径长度。如果不存在从源点至相应顶点的路径,输出-1。
请注意行尾输出换行。
【样例输入】
4 1 **//这里的1表示第2个顶点,0-1-2-3共计4个顶点,下图为有向图的邻接矩阵。**
0 3 0 1
0 0 4 0
2 0 0 0
0 0 1 0
【样例输出】
6 4 7
#include<bits/stdc++.h>
using namespace std;
#define max 100000 // 定义无穷大值,表示不可达
// 定义图结构
typedef struct graph
{
int arcs[100][100]; // 邻接矩阵存储图的边权
int vexnum; // 顶点数量
}Graph;
int path[100]={0}; // 记录最短路径的前驱节点
int dist[100]={0}; // 记录从起点到各顶点的最短距离
bool flag[100]={0}; // 标记顶点是否已找到最短路径
// 初始化函数
void init(Graph g,int s)
{
for(int i=0;i<g.vexnum;i++)
{
if(i!=s)
{
dist[i]=g.arcs[s][i]; // 初始化起点到各顶点的距离
}
}
}
// 找到当前未处理顶点中距离起点最近的顶点
int findmin(Graph g,int s)
{
int min=max; // 初始化为无穷大
int k; // 记录最小顶点的索引
for(int i=0;i<g.vexnum;i++)
{
// 如果顶点i未被处理且到起点的距离小于当前最小值
if(!flag[i]&&g.arcs[s][i]<min)
{
min=g.arcs[s][i]; // 更新最小值
k=i; // 记录顶点索引
}
}
flag[k]=1; // 标记该顶点已处理
return k; // 返回最小顶点的索引
}
// Dijkstra算法主函数
void DIJ(Graph g,int s)
{
flag[s]=1; // 标记起点已处理
init(g,s); // 初始化距离数组
// 循环处理所有顶点(除了起点)
for(int i=1;i<=g.vexnum-1;i++)
{
int m=findmin(g,s); // 找到当前距离起点最近的顶点
// 更新所有未处理顶点到起点的距离
for(int j=0;j<g.vexnum;j++)
{
// 如果通过顶点m到顶点j的路径更短
if(g.arcs[s][j]>g.arcs[s][m]+g.arcs[m][j])
{
g.arcs[s][j]=g.arcs[s][m]+g.arcs[m][j]; // 更新边权
dist[j]=g.arcs[s][j]; // 更新最短距离
path[j]=m; // 记录前驱节点
}
}
}
// 输出结果
for(int k=0;k<g.vexnum;k++)
{
if(dist[k]==max) // 如果距离仍为无穷大
dist[k]=-1; // 输出-1表示不可达
if(k!=s) // 不输出起点到自身的距离
cout<<dist[k]<<' '; // 输出最短距离
}
}
int main()
{
int n,s; // n为顶点数,s为起点
cin>>n>>s;
Graph g;
g.vexnum=n; // 设置顶点数
// 输入邻接矩阵
for(int i=0;i<n;i++)
{
for(int j=0;j<n;j++)
{
cin>>g.arcs[i][j];
if(g.arcs[i][j]==0&&i!=j) // 如果输入为0且不是自环
{
g.arcs[i][j]=max; // 设置为无穷大
}
}
}
DIJ(g,s); // 执行Dijkstra算法
return 0;
}