最短路径之Dijkstra算法
(一)Dijkstra算法
单源最短路径:就是从某一个顶点出发,到图中任意顶点之间的最短路径;
【算法概述】:Dijkstra算法适用于解决单源最短路径的问题。即:从源点到任意指定顶点之间的最短距离的问题;但Dijkstra算法要求所有边的权值非负。看过Prime算法的同学都知道,Dijkstra算法与Prime算法很相似,不同的就是dis数组的更新方式。Dijkstra算法用邻接矩阵存图比较方便。
【算法思想】:先用一个数组记录从源点到图中个顶点直接相连的距离,如果不直接连,就记录为无穷大,然后通过对该数组的更新,使得dis[x]表示从源点到x的最短路径;
1.1 初始化
用邻接矩阵来存图,先进行初始化,自己到自己的距离初始化为0,到另外的顶点的距离初始化为无穷大。并将标记数组都置为0,表示所有顶点都未访问;
void init(){
for(int i=0;i<nodeNum;i++){
for(int j=0;j<nodeNum;j++){
if(i==j)
matrix[i][j]=0;
else
matrix[i][j]=INF;
}
}
memset(visited,0,sizeof(visited));
}
1.2 Dijkstra主体
参数st表示源点,此题是0
第一步:先用min_distance数组储存与0直接相连的顶点之间的距离。并标记0号顶点;然后用一个while死循环来变量所有顶点,最坏的情况就是遍历所有顶点。
第二步:就是在当前的min_distance数组里找一个顶点没有访问过且距离源点最近的点,记录它的顶点下标;
第三步:更新min_distance数组:如果x顶点没有被访问,并且0到x顶点的距离(直接或间接)大于上面min_distance数组最小值加上点p到x点的距离,就对min_distance数组更新: min_distance[x] = min + matrix[p][x];(可以理解为:从源点直接到某点的距离大于间接到某点的距离)
第四步:重复上面的第二步和第三步;
图示:
第一步:此时的dis数组:0 5 2 7;并标记源点0;此时的vis数组:1 0 0 0
void Dijkstra(int start){
//第一个结点进入,标记已走过
for(int i=0;i<nodeNum;i++){
min_distance[i]=matrix[start][i];
}
/*for(int i=0;i<nodeNum;i++){
cout<<min_distance[i];
}*/
visited[start]=true;//表示start结点已经走过
while(true){
//找到距离这个结点最近的节点的坐标
int min=INF;
int index=-1;
for(int i=0;i<nodeNum;i++){
if(visited[i]==false && min_distance[i]<min){
min=min_distance[i];//从起点到index的最小距离
index=i;
}
}
visited[index]=true;//标记已经访问
if(index==-1)//此时所有的节点都已经访问过了
break;
for(int i=0;i<nodeNum;i++){//添加index结点之后更新到达还未访问的点的路径长度
if(visited[i]==false && matrix[index][i]+min<min_distance[i]){
min_distance[i]=matrix[index][i]+min;
}
}
}
}
prime算法与迪杰斯特拉算法的比较很相似
仅在min_distance数组的变化上不同
迪杰斯特拉算法:
for(int i=0;i<nodeNum;i++){//添加index结点之后更新到达还未访问的点的路径长度
if(visited[i]==false && matrix[index][i]+min<min_distance[i]){
min_distance[i]=matrix[index][i]+min;
}
}
if(visited[i]==false&&matrix[index][i]<min_distance[i]){
//当加入新结点(index)之后,达到c(另外一个结点)的距离变小了
min_distance[i]=matrix[index][i];
father[i]=index;
}
全部代码:
#include<iostream>
#include<cstring>
using namespace std;
#define MAX 1000
#define INF 0x3f3f3f3f
/*输入:
4 6
0 1 5
0 2 2
0 3 7
1 3 1
1 2 6
2 3 2
0 3
输出:
0到3的最短路径为:4
vis数组:1 1 1 1
dis数组:0 5 2 4*/
int matrix[MAX][MAX];
bool visited[MAX];
int min_distance[MAX];
int nodeNum;//顶点的数量
int edgeNum;//边的数量
void init(){
for(int i=0;i<nodeNum;i++){
for(int j=0;j<nodeNum;j++){
if(i==j)
matrix[i][j]=0;
else
matrix[i][j]=INF;
}
}
memset(visited,0,sizeof(visited));
}
void Dijkstra(int start){
//第一个结点进入,标记已走过
for(int i=0;i<nodeNum;i++){
min_distance[i]=matrix[start][i];
}
/*for(int i=0;i<nodeNum;i++){
cout<<min_distance[i];
}*/
visited[start]=true;//表示start结点已经走过
while(true){
//找到距离这个结点最近的节点的坐标
int min=INF;
int index=-1;
for(int i=0;i<nodeNum;i++){
if(visited[i]==false && min_distance[i]<min){
min=min_distance[i];//从起点到index的最小距离
index=i;
}
}
visited[index]=true;//标记已经访问
if(index==-1)//此时所有的节点都已经访问过了
break;
for(int i=0;i<nodeNum;i++){//添加index结点之后更新到达还未访问的点的路径长度
if(visited[i]==false && matrix[index][i]+min<min_distance[i]){
min_distance[i]=matrix[index][i]+min;
}
}
}
}
int main(){
cin>>nodeNum>>edgeNum;
int tempx,tempy,cost;
init();
for(int i=0;i<edgeNum;i++){
cin>>tempx>>tempy>>cost;
matrix[tempx][tempy]=cost;
matrix[tempy][tempx]=cost;
}
//矩阵的存储没问题
for(int i=0;i<nodeNum;i++){
for(int j=0;j<nodeNum;j++){
cout<<matrix[i][j]<<" ";
}
cout<<endl;
}
Dijkstra(0);
cout<<endl<<"min_distance数组:";
for(int i=0;i<nodeNum;i++){
cout<<min_distance[i]<<" ";
}
cout<<endl<<"visited数组:";
for(int i=0;i<nodeNum;i++){
cout<<visited[i]<<" ";
}
}
测试数据:
4 6
0 1 5
0 2 2
0 3 7
1 3 1
1 2 6
2 3 2

AcWing 849. Dijkstra求最短路 I
朴素dijkstra算法 :AcWing 849. Dijkstra求最短路 I


朴素写法
#include<bits/stdc++.h>
using namespace std;
const int N=510;
const int INF=0x3f3f3f3f;
int g[N][N];
int dist[N];//dist[i]:从起点到i结点的最少花费
bool st[N];//true:走过 false:没走
int n,m;
void dijk()
{
memset(dist,INF,sizeof(dist));
dist[1]=0;
for(int i=1;i<=n;i++)
{
//纳入新结点
int index=-1;
for(int j=1;j<=n;j++)
{
if(!st[j]&&(index==-1||dist[index]>dist[j]))
index=j;
}
st[index]=true;
//时事更新
for(int j=1;j<=n;j++)
{
dist[j]=min(dist[j],dist[index]+g[index][j]);
}
}
}
int main()
{
cin>>n>>m;
//初始化
memset(g,INF,sizeof(g));//邻接矩阵的初始化,由于求的是最小值,因此初始为无穷大
while(m--)
{
int a,b,c;
cin>>a>>b>>c;
g[a][b]=min(g[a][b],c);//如有重边,则取最小值
}
dijk();
if(dist[n]==INF)
cout<<"-1"<<endl;
else
cout<<dist[n]<<endl;
return 0;
}
本文介绍了Dijkstra算法,用于解决单源最短路径问题,特别是在非负权值边的情况下。算法思想包括初始化邻接矩阵,通过不断找到未访问且距离源点最近的顶点进行路径更新。文章通过与Prime算法的对比,帮助读者理解Dijkstra算法的工作原理,并提供了AcWing 849题目的实例和朴素实现。
1222

被折叠的 条评论
为什么被折叠?



