在四种常用的最短路算法 Dijkstra, SPFA, floyd, Bellman-Ford 中, Dijks 和 SPFA 的使用较为普遍, 对大多数人来说, 也较为熟悉. 然而, floyd 与 BF 算法在一些特定的情况下也是非常管用的, 因此有必要在这里作出一点总结.

Floyd的基本思路就是枚举任意两个点i, j, 再枚举任意的第三个点k, 用d[i][k] + d[j][k] 来松弛d[i][j]的值. 时间复杂度为O(n ^ 3), 优点在于可以求出任意两点之间的距离, 在稠密图中也非常管用.

#include<iostream>
#include<vector>
using namespace std;
const int &INF=100000000;
void floyd(vector<vector<int> > &distmap,//可被更新的邻接矩阵,更新后不能确定原有边
vector<vector<int> > &path)//路径上到达该点的中转点
//福利:这个函数没有用除INF外的任何全局量,可以直接复制!
{
const int &NODE=distmap.size();//用邻接矩阵的大小传递顶点个数,减少参数传递
path.assign(NODE,vector<int>(NODE,-1));//初始化路径数组
for(int k=1; k!=NODE; ++k)//对于每一个中转点
for(int i=0; i!=NODE; ++i)//枚举源点
for(int j=0; j!=NODE; ++j)//枚举终点
if(distmap[i][j]>distmap[i][k]+distmap[k][j])//不满足三角不等式
{
distmap[i][j]=distmap[i][k]+distmap[k][j];//更新
path[i][j]=k;//记录路径
}
}
void print(const int &beg,const int &end,
const vector<vector<int> > &path)//传引用,避免拷贝,不占用内存空间
//也可以用栈结构先进后出的特性来代替函数递归
{
if(path[beg][end]>=0)
{
print(beg,path[beg][end],path);
print(path[beg][end],end,path);
}
else cout<<"->"<<end;
}
int main()
{
int n_num,e_num,beg,end;//含义见下
cout<<"(不处理负权回路)输入点数、边数:";
cin>>n_num>>e_num;
vector<vector<int> > path,
distmap(n_num,vector<int>(n_num,INF));//默认初始化邻接矩阵
for(int i=0,p,q; i!=e_num; ++i)
{
cout<<"输入第"<<i+1<<"条边的起点、终点、长度(100000000代表无穷大,不联通):";
cin>>p>>q;
cin>>distmap[p][q];
}
floyd(distmap,path);
cout<<"计算完毕,可以开始查询,请输入出发点和终点:";
cin>>beg>>end;
cout<<"最短距离为"<<distmap[beg][end]<<",打印路径:"<<beg;
print(beg,end,path);
}

Bellman-Ford是SPFA算法的前身, 时间复杂度为O(VE)…非常慢, 但是可以用于判断负权回路. 常用于差分约束系统中. Bellman-Ford这种写法相当暴力, 直接循环nodeNum次, 每次枚举每一条边, 假如这条边可以用于松弛源点到端点的距离, 则进行松弛. 至于判断负环, 再枚举一遍所有边, 假如存在边仍能用于松弛, 则说明存在负权回路.

#include<iostream>
#include<cstdio>
using namespace std; #define MAX 0x3f3f3f3f
#define N 1010
int nodenum, edgenum, original; //点,边,起点 typedef struct Edge //边
{
int u, v;
int cost;
}Edge; Edge edge[N];
int dis[N], pre[N]; bool Bellman_Ford()
{
for(int i = 1; i <= nodenum; ++i) //初始化
dis[i] = (i == original ? 0 : MAX);
for(int i = 1; i <= nodenum - 1; ++i)
for(int j = 1; j <= edgenum; ++j)
if(dis[edge[j].v] > dis[edge[j].u] + edge[j].cost) //松弛(顺序一定不能反~)
{
dis[edge[j].v] = dis[edge[j].u] + edge[j].cost;
pre[edge[j].v] = edge[j].u;
}
bool flag = 1; //判断是否含有负权回路
for(int i = 1; i <= edgenum; ++i)
if(dis[edge[i].v] > dis[edge[i].u] + edge[i].cost)
{
flag = 0;
break;
}
return flag;
} void print_path(int root) //打印最短路的路径(反向)
{
while(root != pre[root]) //前驱
{
printf("%d-->", root);
root = pre[root];
}
if(root == pre[root])
printf("%d\n", root);
} int main()
{
scanf("%d%d%d", &nodenum, &edgenum, &original);
pre[original] = original;
for(int i = 1; i <= edgenum; ++i)
{
scanf("%d%d%d", &edge[i].u, &edge[i].v, &edge[i].cost);
}
if(Bellman_Ford())
for(int i = 1; i <= nodenum; ++i) //每个点最短路
{
printf("%d\n", dis[i]);
printf("Path:");
print_path(i);
}
else
printf("have negative circle\n");
return 0;
}

关于 Bellman-Ford 与 Floyd 算法的一点感想的更多相关文章

  1. Bellman—Ford算法思想

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

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

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

  3. 图论——最短路径 Dijkstra算法、Floyd算法

    1.弗洛伊德算法(Floyd) 弗洛伊算法核心就是三重循环,M [ j ] [ k ] 表示从 j 到 k 的路径,而 i 表示当前 j 到 k 可以借助的点:红色部分表示,如果 j 到 i ,i 到 ...

  4. 最短路径问题——floyd算法

    floyd算法和之前讲的bellman算法.dijkstra算法最大的不同在于它所处理的终于不再是单源问题了,floyd可以解决任何点到点之间的最短路径问题,个人觉得floyd是最简单最好用的一种算法 ...

  5. 最短路径---Dijkstra/Floyd算法

    1.Dijkstra算法基础: 算法过程比prim算法稍微多一点步骤,但思想确实巧妙也是贪心,目的是求某个源点到目的点的最短距离,总的来说dijkstra也就是求某个源点到目的点的最短路,求解的过程也 ...

  6. ACM/ICPC 之 最短路径-Bellman Ford范例(POJ1556-POJ2240)

    两道Bellman Ford解最短路的范例,Bellman Ford只是一种最短路的方法,两道都可以用dijkstra, SPFA做. Bellman Ford解法是将每条边遍历一次,遍历一次所有边可 ...

  7. poj1860 bellman—ford队列优化 Currency Exchange

    Currency Exchange Time Limit: 1000MS   Memory Limit: 30000K Total Submissions: 22123   Accepted: 799 ...

  8. Dijkstra 算法、Kruskal 算法、Prim算法、floyd算法

    1.dijkstra算法 算最短路径的,算法解决的是有向图中单个源点到其他顶点的最短路径问题. 初始化n*n的数组. 2.kruskal算法 算最小生成树的,按权值加入 3.Prim算法 类似dijk ...

  9. [图论]Floyd 算法小结

    Floyd 算法小结  By Wine93 2013.11 1. Floyd算法简介 Floyd算法利用动态规划思想可以求出任意2点间的最短路径,时间复杂度为O(n^3),对于稠密图, 效率要高于执行 ...

随机推荐

  1. PEP-8 规范1

    代码布局 缩进 每个缩进级别使用4个空格. 延续线应使用Python的隐含线连接在括号,括号和大括号内,或使用悬挂缩进[7],垂直对齐包装元素.使用悬挂式凹痕时,应考虑以下因素;第一行应该没有参数,应 ...

  2. python基础学习笔记——列表及元组

    列表 列表的介绍  列表是python的基础数据类型之一 ,其他编程语言也有类似的数据类型. 列表的索引和切片 列表和字符串一样也拥有索引: lst = ['刘德华','周润发','周杰伦','向华强 ...

  3. JAVA-基础(三)

    Character 类型字符(Character)是围绕字符型(char)的一个简单的包装器.字符(Character)的构造函数如下:Character(char ch)这里ch指定了被创建的字符( ...

  4. 【ajax】全面总结

    Ajax 的全面总结 2017-11-03 山外de楼 JavaScript Ajax在前端开发中有着举足轻重的地位,关于Ajax的使用和注意事项一直是一个重要的话题,借此机会,本文希望对Ajax做一 ...

  5. poj2823 Sliding Window luogu1886 滑动窗口 单调队列

    模板题 #include <iostream> #include <cstring> #include <cstdio> using namespace std; ...

  6. Zipkin和微服务链路跟踪

    https://cloud.tencent.com/developer/article/1082821 Zipkin和微服务链路跟踪 本期分享的内容是有关zipkin和分布式跟踪的内容. 首先,我们还 ...

  7. hexo博客出现“Cannot GET/xxxx”的错误

    最近在github上搭了一个hexo博客系统,非常轻量级的,只需要几句nodejs命令就搭建完成了.我了解了一下,hexo博客是基于nodejs写的,采用ejs模板引擎编写页面. 因为默认的主题风格不 ...

  8. 让boostrap的图片轮播支持滑动效果

    因为最近开发的项目涉及到移动设备上的 HTML5 开发,其中需要实现轮播效果. 然后最快捷的方式,你知道的(Bootstrap),然后原生的 Bootstrap 的 carousel.js 插件并没有 ...

  9. [笔记]BFS算法的python实现

    #!/usr/bin/env python # -*- coding:utf-8 -*- graph = {} graph["you"] = ["alice", ...

  10. 用Navicat Premium快速查看mysql数据库版本信息

    在出现的界面输入命令  select version();