Dijkstra算法,一个名字听起来非常的高大上的算法,他究竟是何方神圣?其实呢这只是一个不是太难而且非常实用的一种算求最短路径的算法,当你真正的掌握之后用起来真的是非常的方便,感觉学习这个算法已经很长一段时间了,但是一直没有去写博客,因为感觉自己并没有完全的掌握它,今天就试一下写一写自己对这个算法的理解吧!!
Dijkstra算法解决的是单源最短路径问题:对于给定的有向网络G=(V,E)及单个源点v,求从v到G的其余各顶点的最短路径。
怎么说呢?这个算法的作用就是给你一个有向图无向图也可以,然后给你一个起点,用 Dijkstra算法可以求出从所给点到到其余个点的最短的距离,这就是 Dijkstra算法的功能。
Dijkstra算法到底是怎么实现求到其他个点的最短路径的?假如现在我们有 6个顶点构成的图(V1 V2 V3 V4 V5 V6),现在呢我们去求V1到其他几个点的最短的距离,首先我们通过一个for循环,可以找到其余个点中距离他最近的点,假如我们找到了v4,那么v1到v4的最短距离一定就是从v1直接到达v4,为什么这么说呢?有的人可能会说也有可能先到其他点然后再到v4啊?可是我们想一想,现在距离v1最近的就是v4了,如果我们先走到其它的点,然后我们再走到v4的话,首先v1到其他的这段路径已经比v1直接到达v4远了,更何况还要加上其他点到v4这段距离没那不是更加的远了吗?所以说v1-v4的最短路径就是直接的到达。好了现在我们已经找到了第一个最短距离的点了,接下来我们要找下一个最短距离了,那么我们又应该怎么找呢?这次呢我们从v1出发,到达v4然后再从v4到达其余各点,如果这次走的距离比v1直接到达这个点的距离近,那么我们就更新v1到达这个点路径,改为从v1-v4-这个点,如果距离比刚开始的远的话,我们就不更新了,更新结束后再从这更新后的距离中,找到一个最短距离,看看到达的是哪一个点,这个点就是这次找到的又一个的最短的路径。为什么这个也是一个最短的路径呢?这个原理和上面的是一样的,在这里就不重新证明了。接下来重复上述的过程我们就可以找到v1到达每一个点的最短路径,
感觉自己写的也不是太好,还是没有把过程给说清楚,可能是自己的能力有限吧。下面再根据一到道题来具体的讲解一下代码的实现吧。
某省自从实行了很多年的畅通工程计划后,终于修建了很多路。不过路多了也不好,每次要从一个城镇到另一个城镇时,都有许多种道路方案可以选择,而某些方案要比另一些方案行走的距离要短很多。这让行人很困扰。
现在,已知起点和终点,请你计算出要从起点到终点,最短需要行走多少距离。Input
本题目包含多组数据,请处理到文件结束。
每组数据第一行包含两个正整数N和M(0<N<200,0<M<1000),分别代表现有城镇的数目和已修建的道路的数目。城镇分别以0~N-1编号。
接下来是M行道路信息。每一行有三个整数A,B,X(0<=A,B<N,A!=B,0<X<10000),表示城镇A和城镇B之间有一条长度为X的双向道路。
再接下一行有两个整数S,T(0<=S,T<N),分别代表起点和终点。Output
对于每组数据,请在一行里输出最短需要行走的距离。如果不存在从S到T的路线,就输出-1.
Sample Input
3 3 0 1 1 0 2 3 1 2 1 0 2 3 1 0 1 1 1 2Sample Output
2 -1
这是一道很典型的求最短路径的题,今天我们就用Dijkstra算法来求一下这个题。
#include<stdio.h>
#include<string.h>
#include<iostream>
using namespace std;
const int maxn=1000+7;
const int INF=0x3f3f3f3f;//代表无穷大;
int n,m;//城镇数和所修的道路数;
int w[maxn][maxn];//用邻接表存图;
bool vis[maxn];//标记是否已经找到起点到达这个点的最短路径;
int d[maxn];//存储每次起点到达这个点此时的最短距离,要不断的更新;
void djk(int st,int ed)// 核心算法,找最短路径;
{
for(int i=0;i<n;i++) //对刚开始的一些数据进行初始化;
{
vis[i]=false;//刚开始起点每个到达每个点的最小值都不知道,所以全部都是false;
d[i]=w[st][i];//刚开始起点到其他各个顶点的距离//
}
vis[st]=true;//起点到达起点的最小值一定是0,所以不用考虑,直接标记;
for(int i=1;i<n;i++) //循环n-1次,每一次循环找到一个最短距离的点;
{
int mn=INF;//找每次的最小值;
int id=-1;//记录最小值的那个点;
for(int j=0;j<n;j++)
{
if(!vis[j]&&d[j]<mn)
{
mn=d[j];
id=j; //不断的更新
}
}
if(id==-1) break;//表示剩下的点都是起点不能到达的;
vis[id]=true; //这个for循环结束找到的是id则个点,标记一下
for(int j=0;j<n;j++)
{
if(!vis[j]&&w[id][j]!=INF) //更新vis的值;
{
if(d[j]>d[id]+w[id][j])
d[j]=d[id]+w[id][j];
}
}
}
printf("%d\n", (d[ed] == INF) ? -1 : d[ed]);
}
int main()
{
while(~scanf("%d %d",&n,&m))
{
for(int i=0;i<n;i++) //对刚开始的邻接矩阵进行初始化,
{ //每一个点到达其他点的距离都是无穷大;
for(int j=0;j<n;j++) //到达自己的距离是0;
{
if(i==j)w[i][i]=0;
else w[i][j]=w[j][i]=INF;
}
}
int u,v,val;//输入每一条边,起点,终点还有权值;
while(m--) //建造邻接矩阵;
{
scanf("%d %d %d",&u,&v,&val);
w[u][v]=w[v][u]=min(w[u][v],val);//防止给的有多条重复的边,我们取边的最小值;
}
int st,ed;//起点和终点;
scanf("%d %d",&st,&ed);
djk(st,ed);
}
return 0;
}