最短路径算法:
1:Dijkstra 2:Floyd 3:Bellman-Ford 4:SPFA 5:A*
这五种最短路径算法初学的时候非常容易混淆,因为他们的松弛方法都差不多,而他们的核心却又与松弛有着很密切的关系,所以很难去辨别区别。
1:Dijkstra
Dijkstra算法适用于单源最短路,也就是从一个点到终点,过程比较贪心,逻辑上是寻求最近点来逐步拓展,以达到局部最优的效果,再由局部最优一一推出全局最优
实现过程:建立dist数组存与原点的距离
1:从全部点中找离确定点(一开始是初始点)最近的点。
2:找到后将它设置为确定点(第二次查找就从他开始了)
3:全局搜索现在这个确定点能扩展到的所有点(也就是与确定点相连的点)(判断能否连通了可以用e[i][j]<inf来判断)
4:松弛操作:看看由原点直达这个点近还是经过确定点近
dist[v]>dist[u]+e[u][v]
5:能扩展就扩展,扩展完后这个点的dist就是到原点的最短距离
6:那么扩展到dist[n]的话,最短距离就是dist[n]
整体思想:找最近点将它们达到的点逐步扩展,更新他们到原点的最短距离。
代码链接:(精简代码+堆优化)
https://blog.csdn.net/Syclus/article/details/123093141?spm=1001.2014.3001.5501
代码:二维存数版本
#include<stdio.h>
#include<iostream>
#include<algorithm>
#include<cstring>
using namespace std;
int main()
{
int e[10][10],dis[10],book[10],n,m,t1,t2,t3,u,v,min;
int inf=99999999;
cin>>n>>m;
for(int i=1;i<=n;i++)
{
for(int j=1;j<=n;j++)//初始化过程
{
if(i==j)//对角线为0(与自身的距离=0)
e[i][j]=0;
else
e[i][j]=inf;
}
}
for(int i=1;i<=m;i++)
{
cin>>t1>>t2>>t3;
e[t1][t2]=t3;
}
for(int i=1;i<=n;i++)//初始化dis,与1的距离
dis[i]=e[1][i];
memset(book,0,sizeof book);//看看当前位置有没有被确定
book[1]=1;//1点开始走当然确定了
for(int i=1;i<=n-1;i++)//大循环为n-1次,就一计数的
{//更新n-1个点所以才这样
min=inf;
for(int j=1;j<=n;j++)//找最近点
{
if(book[j]==0 && dis[j]<min)//走过就不用了
{
min=dis[j];
u=j;
}
}
book[u]=1;//确定最近点
for(v=1;v<=n;v++)
{
if(e[u][v]<inf)//能联通
{
if(dis[v]>dis[u]+e[u][v])
dis[v]=dis[u]+e[u][v];
}
}
}
for(int i=1;i<=n;i++)
cout<<dis[i]<<" ";
cout<<endl;
return 0;
}
2:Floyd(自由:任意两点最短路、过前几个点求最短路)
Floyd算法适用于多源最短路问题,求的是任意两个点的最短路问题,注重的是这个最短路径有没有考虑到所有点,总共三层循环On3,内两层循环统计只考虑过一点的话任意两点之间的最短路(i,j之间最短的距离),最外层循环过k点。这个完全可以根据需求来定,想过几点求最短路,或者哪一点到哪一点都可以。
代码:
for(int k=1;k<=n;k++)//记住是先算只允许经过1点更新完后,再更新只经过2点
{//所以一遍一遍更新下来,最短路会越来越完善
for(int i=1;i<=n;i++)
{
for(int j=1;j<=n;j++)
{
if(e[i][j]>e[i][k]+e[k][j])//过k点的话可不可以优化
e[i][j]=e[i][k]+e[k][j];
}
}
}
3:Bellman-Ford算法:(有负权边)
算法思路:
1.迭代n次(假设迭代了k次,含义:从1号点,走不超过k条边到达所有点的最短距离)
2.每次循环所有边,for(所有边 a,b,w)
3.每次松弛操作:dist[b]=min(dist[b],dist[a]+w)
(可以保证三角不等式,每一个dist[b]<dist[a]+w)
(遇到有边数限制的题目,用backup数组备份一下上次的迭代结果,防止数据串联)