在四种常用的最短路算法 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. zigbee 中 OSAL 事件传递机制和消息传递机制

    一.概述 OSAL (Operating System Abstraction Layer) ,翻译为"操作系统抽象层". OSAL 就是一种支持多任务运行的系统资源分配机制.OS ...

  2. 虚拟化技术xen,kvm,qemu区别

    虚拟化类型 全虚拟化(Full Virtualization) 全虚拟化也成为原始虚拟化技术,该模型使用虚拟机协调guest操作系统和原始硬件,VMM在guest操作系统和裸硬件之间用于工作协调,一些 ...

  3. ASP.NET Web网站中App_Code文件夹的作用及使用场景

    原文地址:Web Site项目和ASP.NET Web Application中App_Code文件夹的作用作者:宾的宾 我现在要建一个ASP.NET的网站了,不难吧,开始动手.如下图: 这种方法建立 ...

  4. C++ 虚函数&纯虚函数&抽象类&接口&虚基类(转)

    http://www.cnblogs.com/fly1988happy/archive/2012/09/25/2701237.html 1. 多态 在面向对象语言中,接口的多种不同实现方式即为多态.多 ...

  5. STM8 EEPROM心得

    对于STM8来说,其内部的EEPROM确实是个不错的东西,而且STM8S103/105价格已经非常便宜了,当然也可以用STM8S003/005代替,而且价格更便宜,大概在,1.2/2.0元左右,比10 ...

  6. [git 学习篇] 创建公钥

    http://riny.net/2014/git-ssh-key/ 1 安装 windows gitbash    msysgit是Windows版的Git,从https://git-for-wind ...

  7. tomcat(不仅仅是tomcat)通过熵池解决在linux启动应用慢

    tomcat启动过程中报错 -Jul- ::] org.apache.catalina.startup.HostConfig.deployDirectory Deploying web applica ...

  8. 【bzoj3680】吊打XXX 随机化

    题目描述 gty又虐了一场比赛,被虐的蒟蒻们决定吊打gty.gty见大势不好机智的分出了n个分身,但还是被人多势众的蒟蒻抓住了.蒟蒻们将n个gty吊在n根绳子上,每根绳子穿过天台的一个洞.这n根绳子有 ...

  9. Angular JS知识小总结

    1.什么是Angular JS? AngularJS 是一个为动态WEB应用设计的 JavaScript结构框架. 2.Angular JS的用处? --它是为了克服HTML在构建应用上的不足而设计 ...

  10. 微软2014实习生及秋令营技术类职位在线测试(题目1 : String reorder)

    题目1 : String reorder 时间限制:10000ms 单点时限:1000ms 内存限制:256MB Description For this question, your program ...