什么是最短路径问题?

简单来讲,就是用于计算一个节点到其他所有节点的最短路径。

单源最短路算法:已知起点,求到达其他点的最短路径。

常用算法:Dijkstra算法、Bellman-ford算法、SPFA算法

多源最短路算法:求任意两点之间的最短路径。

常用算法:floyd算法

单源最短路径——Dijkstra

Dijkstra算法是经典的最短路径算法,用于计算一个节点到其他所有节点的最短路径。

主要特点是以起始点为中心向外层层扩展,直到扩展到终点为止。

时间复杂度:O(n^2)

处理问题:单源、无负权、有向图、无向图最短路径

不能使用的情况:边中含有负权值(无法判断)

#define INF 0x3f3f3f3f

int e[Max][Max];//e[i][j]代表从i->j的距离,不通设为无穷大
int dis[Max];//dis[i]代表从起点到i的最短距离
bool book[Max];//book[i]代表点i是否在S中
int n;//n个顶点
int s;//起点 void Dijkstra()
{
for(int i=;i<=n;i++)//初始化dis数组
dis[i]=e[s][i]; for(int i=;i<=n;i++)//初始化book数组
book[i]=;
dis[s]=;
book[s]=; for(int i=;i<=n-;i++)//Dijkstra算法核心语句
{
int minDis=INF;
int k;//找到与s最近的顶点k
for(int j=;j<=n;j++)
{
if(book[j]== && dis[j]<minDis)
{
minDis=dis[j];
k=j;
}
}
book[k]=; for(int j=;j<=n;j++)//“松弛”过程
{
if(e[k][j]<INF)
{
if(dis[j]>dis[k]+e[k][j])
dis[j]=dis[k]+e[k][j];
}
}
}
}

基本思想:把带权图中所有的点分为两部分S∪U,S为已经求出从起点到该点的最短路径的点集合,U中为未确定最短路径的点集合。把U中的点一个一个加入到S中,最后求出全部最短路径。

如何把U中的点加入S中呢?

①初始时,S只包含源点s,即S={s},dis[s]=0。U包含除v外的其他顶点,即U={其余顶点},若s与U中顶点u有边,则dis[u]=e[s][u],否则,dis[u]=∞。

②从U中找到一个与源点s距离最小(min(dis[]))的顶点k,把k加入S中,dis[k]确定(仔细想想,s与k最短路径必定是dis[k]=e[s][k],找不到更短的)。

③以k为新考虑的中间点,修改源点s到U中各顶点的距离dis[]:若从源点s到顶点u的距离(dis[k]+e[k][u],经过顶点k)比原来距离(dis[u],不经过顶点k)短,则修改顶点u的距离值,修改后的距离值的顶点k的距离加上边上的权。(这一过程称为“松弛”)

④重复步骤②和③直到所有顶点都包含在S中。

算法优化:这里面每次都要寻找距离最短的那个点和距离,时间复杂度为O(n),可以用“堆”来优化,是时间复杂度降为O(lgn)。

算法过程详解:http://ahalei.blog.51cto.com/4767671/1387799

单源最短路径——Bellman-ford算法

求单源最短路径,可以判断有无负权回路(若有,则不存在最短路), 时效性较好,时间复杂度O(VE)。

处理问题:单源、可有负权、有向图、无向图最短路径

注:下面代码为有向图最短路径

#define INF 0x3f3f3f3f

struct Edge{
int u;//起
int v;//终
int weight;//长度
}; Edge edge[maxm];//用来存储所有的边
int dis[maxn];//dis[i]表示源点到i的最短距离
int n,m;//n个点,m条边
int s;//源点 bool Bellmen_ford()
{
for(int i=;i<=n;i++)//初始化
dis[i]=INF; dis[s]=;//源节点到自己的距离为0 for(int i=;i<n;i++)//松弛过程,计算最短路径
{
for(int j=;j<=m;j++)
{
if(dis[edge[j].v]>dis[edge[j].u]+edge[j].weight)//比较s->v与s->u->v大小
dis[edge[j].v]=dis[edge[j].u]+edge[j].weight;
}
} for(int j=;j<=m;j++)//判断是否有负边权的边
{
if(dis[edge[j].v]>dis[edge[j].u]+edge[j].weight)
return false;
} return true;
}

基本思想:bellman-ford的思想和dijkstra很像,其关键点都在于不断地对边进行松弛。而最大的区别就在于前者能作用于负边权的情况。其实现思路是在求出最短路径后,判断此刻是否还能对便进行松弛,如果还能进行松弛,便说明还有负边权的边。

单源最短路径——SPFA算法

上一种算法其实不好用,复杂度太高,SPFA算法是Bellman-ford算法的队列优化,比较常用。SPFA算法在负边权图上可以完全取代Bellman-ford算法,另外在稀疏图中也表现良好。但是在非负边权图中,为了避免最坏情况的出现,通常使用效率更加稳定的Dijkstra算法,以及它的使用堆优化的版本。通常的SPFA算法在一类网格图中的表现不尽如人意。不是很稳定,不如Dijkstra。

处理问题:单源、可有负权、有向图、无向图最短路径(自身其实无法处理负权)

#define INF 0x3f3f3f3f

int dis[MAX];//dis[i]表示起点到i的最短距离
bool vis[MAX];//是否访问过点i
int e[MAX][MAX];//矩阵 int n,m;//点和边的数量
int s;//源点 void SPFA()
{
for(int i=;i<=n;i++)//初始化
{
dis[i]=INF;
vis[i]=false;
}
queue<int> q;
q.push(s);
dis[s]=;
vis[s]=true; while(!q.empty())
{
int cur=q.front();
q.pop();
vis[cur]=false;
for(int i=;i<=n;i++)
{
if(e[cur][i]!=INF&&dis[i]>=dis[cur]+e[cur][i])
{
dis[i]=dis[cur]+e[cur][i];
if(!vis[i])
{
vis[i]=true;
q.push(i);
}
}
}
}
}

算法思想:

设立一个队列用来保存待优化的点,优化时每次取出队首结点u,并且用u点当前的最短路径估计值对u点所指向的结点v进行松弛操作,如果v点的最短路径估计值有所调整,且v点不在当前的队列中,就将v点放入队尾。这样不断从队列中取出结点来进行松弛操作,直至队列空为止。

算法过程详解:http://www.360doc.com/content/13/1208/22/14357424_335569176.shtml

例题:http://ac.jobdu.com/problem.php?pid=1008

多源最短路径——Floyd算法

Floyd算法是一种利用动态规划思想的计算加权图中多源点之间最短路径的算法。可以正确处理有向图或负权的最短路径问题。

时间复杂度:O(N^3)

空间复杂度:O(N^2)

处理问题:多源、可有负权、有向图、无向图最短路径

int e[Max][Max];//e[i][j]代表从i->j的距离,不通设为无穷大
int n;//n个顶点
//Floyd算法
void Floyd()
{
for(int k=1;k<=n;k++)//遍历所有的中间点
{
for(int i=1;i<=n;i++)//遍历所有的起点
{
for(int j=1;j<=n;j++)//遍历所有的终点
{
if (e[i][j]>e[i][k]+e[k][j])//如果当前i->j的距离大于i->k->j的距离之和
e[i][j]=e[i][k]+e[k][j];//更新从i->j的最短路径
}
}
}
}

算法思想:

①如果不允许有中转点,那么最短路径就是我们的e[][]原始矩阵;

②现在只允许经过1号顶点进行中转,判断e[i][1]+e[1][j]是否比e[i][j]要小,修改e[][];

③接下来只允许经过1和2号顶点进行中转……

④最后,允许经过1~n号所有顶点进行中转,得到最后的e[][],就是要求的任意两点之间的最短路程。

这里面是动态规划思想的体现。状态转移方程:e[i,j]=max{e[i,k]+e[k,j],e[i,j]};

算法过程:对于每一对顶点 i 和 j,看看是否存在一个顶点 k 使得从 i 到 k 再到 j 比已知的路径更短。如果是,则更新它。

算法过程详解:http://ahalei.blog.51cto.com/4767671/1383613

另外,特别鸣谢,本文参考(含大量例题):http://blog.csdn.net/hjd_love_zzt/article/details/26739593

作者: AlvinZH

出处: http://www.cnblogs.com/AlvinZH/

本人Github:https://github.com/Pacsiy/JobDu

本文版权归作者AlvinZH和博客园所有,欢迎转载和商用,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文连接,否则保留追究法律责任的权利.

四大算法解决最短路径问题(Dijkstra+Bellman-ford+SPFA+Floyd)的更多相关文章

  1. Bellman - Ford 算法解决最短路径问题

    Bellman - Ford 算法: 一:基本算法 对于单源最短路径问题,上一篇文章中介绍了 Dijkstra 算法,但是由于 Dijkstra 算法局限于解决非负权的最短路径问题,对于带负权的图就力 ...

  2. Floyd算法解决最短路径问题

    时间限制:10000ms 单点时限:1000ms 内存限制:256MB 描述 万圣节的中午,A和B在吃过中饭之后,来到了一个新的鬼屋!鬼屋中一共有N个地点,分别编号为1..N,这N个地点之间互相有一些 ...

  3. Dijkstra算法解决单源最短路径

    单源最短路径问题:给定一个带权有向图 G = (V, E), 其中每条边的权是一个实数.另外,还给定 V 中的一个顶点,称为源.现在要计算从源到其他所有各顶点的最短路径长度.这里的长度是指路上各边权之 ...

  4. Bellman—Ford算法思想

    ---恢复内容开始--- Bellman—Ford算法能在更普遍的情况下(存在负权边)解决单源点最短路径问题.对于给定的带权(有向或无向)图G=(V,E),其源点为s,加权函数w是边集E的映射.对图G ...

  5. 《算法导论》读书笔记之图论算法—Dijkstra 算法求最短路径

    自从打ACM以来也算是用Dijkstra算法来求最短路径了好久,现在就写一篇博客来介绍一下这个算法吧 :) Dijkstra(迪杰斯特拉)算法是典型的最短路径路由算法,用于计算一个节点到其他所有节点的 ...

  6. 【算法导论】单源最短路径之Dijkstra算法

    Dijkstra算法解决了有向图上带正权值的单源最短路径问题,其运行时间要比Bellman-Ford算法低,但适用范围比Bellman-Ford算法窄. 迪杰斯特拉提出的按路径长度递增次序来产生源点到 ...

  7. 最短路径问题---Dijkstra算法详解

    侵删https://blog.csdn.net/qq_35644234/article/details/60870719 前言 Nobody can go back and start a new b ...

  8. 最短路径:Dijkstra & Floyd 算法图解,c++描述

    <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/ ...

  9. 数据结构与算法--最短路径之Dijkstra算法

    数据结构与算法--最短路径之Dijkstra算法 加权图中,我们很可能关心这样一个问题:从一个顶点到另一个顶点成本最小的路径.比如从成都到北京,途中还有好多城市,如何规划路线,能使总路程最小:或者我们 ...

随机推荐

  1. dos中的延迟环境变量扩展

    一.前言 昨天在写bat脚本的时候,发现在for里面的set命令竟然不起作用!于是搜了一下,前面的几篇都有说到这个是变量扩展的问题,但是什么是变量扩展?为什么会出现这种问题,什么又是延迟环境变量扩展? ...

  2. C++ std::unordered_map

    std::unordered_map template < class Key, // unordered_map::key_type class T, // unordered_map::ma ...

  3. centos7.0查看有没有运行mysql

    centos7自带是mariadb,一个mysql的变种. 查看有没有安装过:yum list installed mysql*rpm -qa | grep mysql* 安装mysql软件(mari ...

  4. 32 取一个整数a从右端开始的4-7位

    题目:取一个整数a从右端开始的4-7位 public class _032FetchDigit { public static void main(String[] args) { fetchDigi ...

  5. 大佬福利之在你眼中 Web 3.0 是什么?(转)

    web 3.0 Web 3.0一词包含多层含义,用来概括互联网发展过程中某一阶段可能出现的各种不同的方向和特征.Web 3.0 充满了争议和分歧,它到底应该什么样?具体的标志点又是什么? Web 2. ...

  6. kafka (搜索) 在idea api操作(官方apihttp://kafka.apache.org/documentation/#producerapi)

     https://blog.csdn.net/isea533/article/details/73822881        这个不推荐,可以看一下(https://www.cnblogs.com/b ...

  7. 3、Semantic-UI之定义容器

    3.1 定义容器   在主流的前端框架中都会有容器的概念,但是在Semantic-UI中,如果要定义容器需要通过class="ui container",定义容器后,浏览器会根据不 ...

  8. [安裝] Ubuntu Server 初试

    在 Delphi 10.2 Tokyo 版里将支持 Linux 系统,先做一下学习记录: 安装 Ubuntu Server: 安装方法请参考官方教学影片: https://community.emba ...

  9. centos 安装erlang rpm包互相依赖问题

    在项目中使用 centos 6.5 mini 版本(网络隔离,无法上外网),因测试需要使用到 erlang 环境. erlang rpm 包下载地址:https://www.erlang-soluti ...

  10. 使用javascript随机生成斗地主玩家手牌

    学习javascript估摸着有半个多月了,好歹自己有过编程基础,学的还算轻松,不过js里的面向对象是真的打脑壳,但都但不懂,和我以前学过的c#简直相差太远 今天写了个随机生成斗地主玩家手牌的代码,自 ...