Dijkstra 算法
只适用于正权边
思想是贪心的思想
朴素版Dijkstra 适合稠密图
朴素Dijkstra 思路
集合S为已经确定最短路径的点集。
初始化距离: 1 号结点的距离为零,其他结点的距离设为无穷大(看具体的题)。
循环 n 次,每一次将集合 S 之外距离最短 X 的点加入到 S 中去(这里的距离最短指的是距离 1 号点最近。点 X 的路径一定最短,基于贪心,严格证明待看)。然后用点 X 更新 X 邻接点的距离。
时间复杂度分析
寻找路径最短的点:O(n^2)O(n2)
加入集合S:O(n)O(n)
更新距离:O(m)O(m)
所以总的时间复杂度为 O(n^2)O(n2)
稠密图用邻接矩阵存图。
#include<iostream>#include<cstring>#include<cstdio>#include<algorithm>
using namespace std;
const int N = 510;
int g[N][N], dis[N];bool vis[N]; // 依据访问过与否将所有节点分成两个部分(集合)
int n, m;
void dijkstra(int s){
memset(dis, 0x3f, sizeof(dis));
memset(vis, 0, sizeof(vis));
dis[s] = 0;
for(int i = 1; i <= n; i++)
{
// 确定集合中距离初始节点最近的点 t
int t = -1;
for(int j = 1; j <= n; j++)
{
if(!vis[j] && (t == -1 || dis[j] < dis[t]))
t = j;
}
vis[t] = true; // 加入 S 集合
// 从 t 出发,更新相邻点的 dis
for(int j = 1; j <= n; j++)
dis[j] = min(dis[j], dis[t] + g[t][j]);
}}
int main(){
scanf("%d%d", &n, &m);
memset(g, 0x3f, sizeof(g));
while (m--)
{
int x, y, c;
scanf("%d%d%d", &x