什么是单源最短路算法
第一次学习这个算法时,老师告诉我们,这是一个单源最短路算法
那问题来了,什么是“单源最短路”呢?
其实也很好理解
以最简单的Floyd作比较 → Floyd此处传送
为什么Floyd慢?
因为ta有3层循环
为什么要3层循环呢?
因为ta计算的是任意两个点之间的最短路径
而当你学到后面就会知道Dijkstra的时间复杂度为O(n*n)
Floyd的时间复杂度为O(n*n*n)
这就是因为Dijkstra是“单源最短路”算法(感觉我说了一堆废话
综上所述(我也不知道上面讲了些啥):
单源最短路是只计算一个点到其他点的最短路径
举个简单的例子
这是一个有向图
让我们求1点到各点(即2 3 4 5)的最短的距离
如果要用Floyd做,直接3层循环就可以了,但是,我很无聊,非不用Floyd做,用Dijkstra做
然后我们来分一下步骤:
1.首先,我们定义一个数组dis[6],代表1到所有点的距离,依次是1到1 2 3 4 5的距离,先把他们都 赋值成无穷大
//2.数组定义完之后,要放点东西啊
//2.被篮圈圈住的三个点,都是1 一次性就能到达的(即,1出度对应的点
2.我们就先把这3个点的dis更新为1到他们的边权值,如下图 ↓
***注:这里dis数组里的值并不是最短路径,也不是最终答案,dis数组会一直变化,直到把所有边 、所有点都操作一遍后才是最终答案
***注:这里1的无穷大只是为了区分,实际代码里自己到自己的距离是0,所以本文章dis[1]的值实际上都是0
3.刚刚计算的是1的出度对应的点,现在再看2的出边
//4.然后我们发现从2出发只能到达5,所以把dis[5]的值更新
*注:dis数组里的所有值都是从出发点开始的路径,也就是指此题中的dis值都是1到一个点的值
4.然后就可以更新成这个样子 ↓
//5.2的出边我们算完了,就计算3的
//5.然后发现3能到达2和5 ↓
//5.但2和5的dis都有值了
//5.那么就比较经过3的dis和目前dis数组里的值,取小的值
//5.我们可以计算出1→3→2的dis为5,比原来的dis[2](10)要小,更新
1→3→5的dis为3,比原来的dis[5](15)要小,更新
5.dis数组值更新如下 ↓
//6.以此类推,再计算4出边对应的点
//6.具体过程和前面2、3的过程一样
//6.计算3、5经过4的dis,再作比较
6.更新如下 ↓
//6.因为从经过4的dis值比原来的dis[3],dis[5]都小,所以不用更新
7. 5没有对应的出边和点,不用操作dis
8.所有点都遍历过一遍了,此时的dis数组储存的也都是1到其他点最短路径了
9.输出(或者做别的操作,看题目),程序圆满结束
对了,还有一个专有名词——松弛
简单说一下
其实计算并更新dis的值就是松弛(其实知不知道都一样
(够简单的吧
是时候上代码了
题目
计算点1到其他点(2 3 4 5)的最短路径,依次输出
#include <bits/stdc++.h>
using namespace std;
int e[1005][1005]; //存图
int dis[1005];
int n,m; //n代表点数,m代表边数
const int inf=2147483647;
int flag[1005]; //标记数组,保证每个点都可以作为经行dis计算的初始点
int minn=inf;
int uu;
int main()
{
cin>>n>>m;
//初始化图
for(int i=1;i<=n;i++)
for(int j=1;j<=n;j++)
{
if(i==j) e[i][j]=0;
else e[i][j]=inf;
}
//输入
for(int i=1;i<=m;i++)
{
int u,v,w;
//u到v有一条长度w的边(有向图
cin>>u>>v>>w;
e[u][v]=w;
}
//初始化dis数组
for(int i=1;i<=n;i++)
dis[i]=e[1][i];
//初始化标记数组
memset(flag,0,sizeof(0));
flag[1]=1; //从1开始遍历
//Djakarta核心
for(int i=1;i<=n-1;i++) //i代表现在遍历的起始点编号
{
minn=inf;
for(int j=1;j<=n;j++) //j代表从1经过出发点能够到达j
{
if(flag[j]==0 && dis[j]<minn)
{
minn=dis[j]; //更新最小值
uu=j; //记录能够经行转换长度的点编号
}
}
for(int j=1;j<=n;j++)
{
if(e[uu][j]<inf) //判断有边可走
{
if(dis[j]>dis[uu]+e[uu][j]) //经行松弛
dis[j]=dis[uu]+e[uu][j];
}
}
}
for(int i=1;i<=n;i++)
cout<<dis[i]<<' ';
return 0;
}
看到这里,点个赞吧(逃