[算法读书笔记C++,搜索与图论]dijkstra算法
Posted 凌星An
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了[算法读书笔记C++,搜索与图论]dijkstra算法相关的知识,希望对你有一定的参考价值。
介绍
Dijkstra算法是由荷兰计算机科学家狄克斯特拉于1959年提出的,因此又叫狄克斯特拉算法,是从一个顶点到其余各顶点的最短路径算法。
应用: 解决有权图中最短路径问题。
思想: 从起始点开始,采用贪心算法的策略,每次遍历到始点距离最近且未访问过的顶点的邻接点,直到扩展到终点为止。
下面,我们演示一下具体的过程
有向图 如下面所示:
起点(源点)为v1 ,终点为v4
从起点v1出开始遍历,标记v1已经被遍历过
遍历v1的邻接点,找到距离最近的邻接点 :v2
因为 v1->v2距离为7,v1->v4距离为70
从v2开始遍历,标记v2已经被遍历过了
遍历v2的邻接点,找到距离最近的邻接点 : v3
遍历v3的邻接点,找到距离最近的邻接点 : v4
故找到了v1到v4的最短路径为v1->v2->v3->v4 ,长度为18
伪代码:
const int N //图中节点个数
int dist[N]; //起点到节点i的路径长度
bool s[N];//当前节点是否已经去顶从起点到该店的最短路径
int g[N][N];//邻接矩阵,存储图
int dijkstra(int start,int end)
dist中起点位置初始化为0,其他位置初始化为∞(无穷大的数字)
//遍历1~N节点
for(int i=1;i<=N;i++)
//把没有访问过的且距离起点最近的点赋值给t
int t=-1;
for(int j=1;j<=n;j++)
if(!s[i]&&(t==-1||dist[t]>dist[j]))
t=j;
//使用t更新邻接点的最短距离
for(int j=1;j<=n;j++)
if(dist[j]>dist[t]+g[t][j])
dist[j]=dist[t]+g[t][j];
//返回起点到终点的最短距离
return dist[end];
题目练习
- Dijkstra求最短路 I
给定一个 n 个点 m 条边的有向图,图中可能存在重边和自环,所有边权均为正值。 请你求出 1 号点到 n 号点的最短距离,如果无法从 1
号点走到 n 号点,则输出 −1。
输入格式 第一行包含整数 n 和 m。 接下来 m 行每行包含三个整数 x,y,z,表示存在一条从点 x 到点 y 的有向边,边长为 z。输出格式 输出一个整数,表示 1 号点到 n 号点的最短距离。 如果路径不存在,则输出 −1。
数据范围 1≤n≤500, 1≤m≤105, 图中涉及边长均不超过10000。
输入样例: 3 3 1 2 2 2 3 1 1 3 4
输出样例: 3
思路:
建立图,使用dijkstra算法求取答案即可。
代码:
#include<iostream>
#include<algorithm>
#include<cstring>
using namespace std;
const int N=500+10;
//邻接矩阵
int g[N][N];
bool s[N];
int dist[N];
int dijkstra(const int n)
//初始化
memset(dist,0x3f,sizeof dist);
memset(s,0,sizeof s);
dist[1]=0;
for(int i=1;i<n;i++)
//找不在s中的距离最近的点,赋值给t
int t=-1;
for(int j=1;j<=n;j++)
if(!s[j]&&(t==-1||dist[j]<dist[t]))
t=j;
//将t加入s
s[t]=true;
//用t更新其他点的距离
for(int j=1;j<=n;j++)
if(dist[j]>dist[t]+g[t][j])
dist[j]=dist[t]+g[t][j];
//如果走不到终点,则终点距离并不会被初始化
if(dist[n]==0x3f3f3f3f)
return -1;
return dist[n];
int main()
//初始化,没有边的两点距离为无穷大
memset(g,0x3f,sizeof g);
int n=0,m=0;
scanf("%d%d",&n,&m);
for(int i=1;i<=m;i++)
int a=0,b=0,c=0;
scanf("%d%d%d",&a,&b,&c);
//两点之间可能包含重边,我们只需要保存最小的那条边
g[a][b]=min(g[a][b],c);
printf("%d\\n",dijkstra(n));
return 0;
堆优化版本
在上面的dijkstra算法当中,时间复杂度为O(n^2);
倘若边数远小于n^2,我们需要对它进行优化的话, 遍历1~N节点 和 使用t更新邻接点的最短距离 这两方面,无法在进行简化。而对于 找不在s中的距离最近的点,赋值给t 我们可以使用堆来进行优化,取出最短路径的复杂度降为O(1);每次调整的复杂度降为O(elogn);e为该点的边数,所以复杂度降为O((m+n)logn)
伪代码
const int N //图中节点个数
const int M=N*N //图中有向边的数量
int dist[N]; //起点到节点i的路径长度
bool s[N];//当前节点是否已经去顶从起点到该店的最短路径
//邻接矩阵,存储图
int head[N],e[M],ne[M],w[M],idx=0;
int dijkstra(int start,int end)
dist中起点位置初始化为0,其他位置初始化为∞(无穷大的数字)
heap //小根堆
heap.push(start);//把起点放入堆中
//遍历1~N节点
while(heap.size())
//找到距离最近且没有被访问过的点
int t=heap.top();
if(s[t])
continue;
s[t]=true;
//使用t更新邻接点的最短距离
for(int i=head[t];i!=-1;i=ne[i])
int j=e[i];
if(dist[j]>dist[t]+w[i])
dist[j]=dist[t]+w[i];
heap.push(dist[j]);
//返回起点到终点的最短距离
return dist[end];
题目练习
- Dijkstra求最短路 II
给定一个 n 个点 m 条边的有向图,图中可能存在重边和自环,所有边权均为非负值。 请你求出 1 号点到 n 号点的最短距离,如果无法从 1号点走到 n 号点,则输出 −1。
输入格式 第一行包含整数 n 和 m。 接下来 m 行每行包含三个整数 x,y,z,表示存在一条从点 x 到点 y 的有向边,边长为 z。
输出格式 输出一个整数,表示 1 号点到 n 号点的最短距离。 如果路径不存在,则输出 −1。
数据范围 1≤n,m≤1.5×105, 图中涉及边长均不小于 0,且不超过 10000。
输入样例: 3 3 1 2 2 2 3 1 1 3 4
输出样例: 3
#include<iostream>
#include<algorithm>
#include<cstring>
#include<queue>
using namespace std;
const int N=1.5*1e5+10;
typedef pair<int,int> PII;
//邻接矩阵
int head[N],w[N],e[N],ne[N],idx=0;
bool s[N];
int dist[N];
void add(int a,int b,int c)
e[idx]=b,w[idx]=c,ne[idx]=head[a],head[a]=idx++;
int dijkstra(const int n)
memset(dist,0x3f,sizeof dist);
memset(s,0,sizeof s);
dist[1]=0;
priority_queue<PII,vector<PII>,greater<PII>> heap;
//距离 点
heap.push(0,1);
while(heap.size())
//找不在s中的距离最近的点,赋值给t
auto tmp=heap.top();
heap.pop();
int t=tmp.second,dis=tmp.first;
if(s[t])
continue;
//将t加入s
s[t]=true;
//用t更新其他点的距离
for(int i=head[t];i!=-1;i=ne[i])
int j=e[i];
if(dist[j]>dist[t]+w[i])
dist[j]=dist[t]+w[i];
heap.push(dist[j],j);
if(dist[n]==0x3f3f3f3f)
return -1;
return dist[n];
int main()
memset(head,-1,sizeof head);
int n=0,m=0;
scanf("%d%d",&n,&m);
for(int i=1;i<=m;i++)
int a=0,b=0,c=0;
scanf("%d%d%d",&a,&b,&c);
add(a,b,c);
printf("%d\\n",dijkstra(n));
return 0;
总结
朴素dijkstra算法,复杂度为O(n^2) ,主要适用于稠密图,即边数m接近于n*n (n为点数) ,图采用邻接矩阵存储
堆优化dijkstra算法,复杂度为O((m+n)logn),主要使用于稀疏图,即边数m远小于n*n (n为点数) ,图采用邻接表存储
以上是关于[算法读书笔记C++,搜索与图论]dijkstra算法的主要内容,如果未能解决你的问题,请参考以下文章
经典树与图论(最小生成树、哈夫曼树、最短路径问题---Dijkstra算法)