最短路算法 (bellman-Ford算法)
贝尔曼-福特算法与迪科斯彻算法类似,都以松弛操作为基础,即估计的最短路径值渐渐地被更加准确的值替代,直至得到最优解。在两个算法中,计算时每个边之间的估计距离值都比真实值大,并且被新找到路径的最小长度替代。 然而,迪科斯彻算法以贪心法选取未被处理的具有最小权值的节点,然后对其的出边进行松弛操作;而贝尔曼-福特算法简单地对所有边进行松弛操作,共|V | − 1次,其中 |V |是图的点的数量。在重复地计算中,已计算得到正确的距离的边的数量不断增加,直到所有边都计算得到了正确的路径。这样的策略使得贝尔曼-福特算法比迪科斯彻算法适用于更多种类的输入。
贝尔曼-福特算法的最多运行O(|V|·|E|)次,|V|和|E|分别是节点和边的数量)。
贝尔曼-福特算法与迪科斯彻算法最大的不同:bellman-Ford算法可以存在负权边,而dijkstra算法不允许出现负权边;
bellman-Ford算法的步骤:
步骤1:初始化图
步骤2 :对每一条边进行松弛操作
步骤3:检查负权环
procedure BellmanFord(list vertices, list edges, vertex source)
// 该实现读入边和节点的列表,并向两个数组(distance和predecessor)中写入最短路径信息 // 步骤1:初始化图
for each vertex v in vertices:
if v is source then distance[v] :=
else distance[v] := infinity
predecessor[v] := null // 步骤2:重复对每一条边进行松弛操作
for i from to size(vertices)-:
for each edge (u, v) with weight w in edges:
if distance[u] + w < distance[v]:
distance[v] := distance[u] + w
predecessor[v] := u // 步骤3:检查负权环
for each edge (u, v) with weight w in edges:
if distance[u] + w < distance[v]:
error "图包含了负权环"
题意:John在N个农场之间有path与wormhole ,path+时间,wormhole-时间;求是否存在某点满足,John 旅行一些 paths和wormholes,回到原点时间为负。
思路:标准bellman-Ford算法;(检查负权环)
#include <iostream>
#include <algorithm>
#include <cstdlib>
#include <ctime>
#include <cmath>
#include <cstdio>
#include <string>
#include <cstring>
#include <vector>
#include <queue>
#include <stack>
#include <set> #define c_false ios_base::sync_with_stdio(false); cin.tie(0)
#define INF 0x3f3f3f3f
#define INFL 0x3f3f3f3f3f3f3f3f
#define zero_(x,y) memset(x , y , sizeof(x))
#define zero(x) memset(x , 0 , sizeof(x))
#define MAX(x) memset(x , 0x3f ,sizeof(x))
#define swa(x,y) {LL s;s=x;x=y;y=s;}
using namespace std ;
#define N 505
#define lowbit(k) k&(-k)
const double PI = acos(-1.0);
const int M = 1e5+;
typedef long long LL ;
int farm, field, path, wormhole, sum;
int dis[N];
struct way{
int Begin, End, Time;
}a[N*N];
bool BellmanFord(){
for(int i = ; i <= field; i++) dis[i] = M; ///初始化操作;
for(int i = ; i < field; i++){ ///松弛操作;
for(int j = ; j <= sum; j++){
if(dis[a[j].End] > dis[a[j].Begin] + a[j].Time)
dis[a[j].End] = dis[a[j].Begin] + a[j].Time;
}
}
for(int i = ; i <= sum; i++) ///检查负权环;
if(dis[a[i].End] >dis[a[i].Begin] +a[i].Time)
return false;
return true;
} int main(){
//freopen("in.txt","r",stdin);
//freopen("out.txt","w",stdout);
//ios_base::sync_with_stdio(false); cin.tie(0);
scanf("%d", &farm);
while(farm--){
int s, e, t, k = ;
scanf("%d%d%d", &field, &path, &wormhole);
for(int i = ; i < path; i++){
scanf("%d%d%d", &s, &e, &t);
k++;
a[k].Begin = s;
a[k].End = e;
a[k].Time = t;
k++;
a[k].Begin = e;
a[k].End = s;
a[k].Time = t;
}
for(int i = ; i < wormhole; i++){
scanf("%d%d%d", &s, &e, &t);
k++;
a[k].Begin = s;
a[k].End = e;
a[k].Time = -t;
}
sum = k;
if(!BellmanFord()) printf("YES\n");
else printf("NO\n");
}
return ;
}
题意:N种货币,M个交易点,每次交易要收佣金,求是否存在增值的方法。
思路:刚好与Bellman-Ford算法相反,检查正权环;
A到B的边权为:B = (A - Cab)*Rab;
discuss里有人讨论环是否包含了S点,其实环没必要包含S点,
因为只要找到了一个可以无限增加财富的环,增加财富后再回到S点就可以了。
所以环是没必要包含S点的。
#include <iostream>
#include <algorithm>
#include <cstdlib>
#include <ctime>
#include <cmath>
#include <cstdio>
#include <string>
#include <cstring>
#include <vector>
#include <queue>
#include <stack>
#include <set> #define c_false ios_base::sync_with_stdio(false); cin.tie(0)
#define INF 0x3f3f3f3f
#define INFL 0x3f3f3f3f3f3f3f3f
#define zero_(x,y) memset(x , y , sizeof(x))
#define zero(x) memset(x , 0 , sizeof(x))
#define MAX(x) memset(x , 0x3f ,sizeof(x))
#define swa(x,y) {LL s;s=x;x=y;y=s;}
using namespace std ;
#define N 505
#define lowbit(k) k&(-k)
const double PI = acos(-1.0);
const int M = 1e5+;
typedef long long LL; int n, m, S, sum;
double Rab, Cab, Rba, Cba, V;
double dis[N];
struct way{
int Begin, End;
double Change, Rate;
}a[N*N]; bool BellmanFord(){
zero(dis);
dis[S] = V;
int sign;
for(int i = ; i <= n; i++){
sign = ;
for(int j = ; j <= sum; j++){
if(dis[a[j].End] < (dis[a[j].Begin] - a[j].Change)*a[j].Rate)
dis[a[j].End] = (dis[a[j].Begin] - a[j].Change)*a[j].Rate;
sign = ;
}
if(!sign)
break;
}
for(int j = ; j <= sum; j++){
if(dis[a[j].End] < (dis[a[j].Begin] - a[j].Change)*a[j].Rate)
return true;
}
return false;
} int main(){
//freopen("in.txt","r",stdin);
//freopen("out.txt","w",stdout);
//ios_base::sync_with_stdio(false); cin.tie(0);
while(~scanf("%d%d%d%lf", &n, &m, &S, &V)){
int x, y, k = ;
for(int i = ; i < m; i++){
scanf("%d%d%lf%lf%lf%lf", &x, &y, &Rab, &Cab,&Rba,&Cba);
++k;
a[k].Begin = x;
a[k].End = y;
a[k].Change= Cab;
a[k].Rate = Rab;
++k;
a[k].Begin = y;
a[k].End = x;
a[k].Change= Cba;
a[k].Rate = Rba;
}
sum = k;
if(BellmanFord()) printf("YES\n");
else printf("NO\n");
}
return ;
}
题意:酋长卖女儿,N个物品,阶级差判断是否连通,金币看作边权。求最小价格。(存在自己到自己的边)
设:dis[i] 为购买i物品需要的最小价格;pre[i] 为阶级;
初始化:dis[i] = prise; else INF;
边权:(A->B) B = A + dis[a[i].money];
关键在于阶级的判断:要保证以a[1]为终点的路径中满足阶级差不大于m;
开始以为边的两点都只要满足[pre[1] - m, pre[1] +m]就可以了;
但是如果边的两点的差值就直接大于m呢?(有人提出了越等级的要求!)
这时候就要满足全部[pre[1]-m,a[1]],[pre[1]-m+1, pre[1]+1]………[pre[1], pre[1] +m];
对于每个物品先标记再求;取其最小值即可;
#include <iostream>
#include <algorithm>
#include <cstdlib>
#include <ctime>
#include <cmath>
#include <cstdio>
#include <string>
#include <cstring>
#include <vector>
#include <queue>
#include <stack>
#include <set> #define c_false ios_base::sync_with_stdio(false); cin.tie(0)
#define INF 0x3f3f3f3f
#define INFL 0x3f3f3f3f3f3f3f3f
#define zero_(x,y) memset(x , y , sizeof(x))
#define zero(x) memset(x , 0 , sizeof(x))
#define MAX(x) memset(x , 0x3f ,sizeof(x))
#define swa(x,y) {LL s;s=x;x=y;y=s;}
using namespace std ;
#define N 505
#define lowbit(k) k&(-k)
const double PI = acos(-1.0);
const int M = 1e5+;
typedef long long LL; int n, m, S, sum, P, L, X;
int dis[N],pre[N];
bool could[N];
struct way{
int Begin, End, Money;
}a[N*N]; void BellmanFord(){
for(int i = ; i <= n; i++)
if(dis[i] == ) dis[i] = M;
for(int i = ; i <= n; i++){
for(int j = ; j <= sum; j++){
if(could[a[j].End] && could[a[j].Begin])
if(dis[a[j].End] > dis[a[j].Begin] + a[j].Money)
dis[a[j].End] = dis[a[j].Begin] + a[j].Money;
}
}
} int main(){
//freopen("in.txt","r",stdin);
//freopen("out.txt","w",stdout);
//ios_base::sync_with_stdio(false); cin.tie(0);
while(~scanf("%d%d", &m, &n)){
zero(dis);zero(pre);
int x, y, k = ;
for(int i = ; i <= n; i++){
scanf("%d%d%d", &P, &L, &X);
dis[i] = P;
pre[i] = L;
for(int j = ; j <= X; j++){
scanf("%d%d", &x, &y);
++k;
a[k].Begin = x;
a[k].End = i;
a[k].Money = y;
}
}
sum = k;
int MIN = M;
for(int i = ; i <= m; i++){
zero(could);
for(int j = ; j <= n; j++){
if(pre[] - (m-i) <= pre[j] && pre[] + i >= pre[j]){
could[j] = true;
//cout<<pre[j]<<" "<<j<<endl;
}
}
BellmanFord();
if(dis[] < MIN) MIN = dis[];
//cout<<dis[1]<<endl;
}
printf("%d\n", MIN);
}
return ;
}
最短路算法 (bellman-Ford算法)的更多相关文章
- Bellman—Ford算法思想
---恢复内容开始--- Bellman—Ford算法能在更普遍的情况下(存在负权边)解决单源点最短路径问题.对于给定的带权(有向或无向)图G=(V,E),其源点为s,加权函数w是边集E的映射.对图G ...
- Bellman - Ford 算法解决最短路径问题
Bellman - Ford 算法: 一:基本算法 对于单源最短路径问题,上一篇文章中介绍了 Dijkstra 算法,但是由于 Dijkstra 算法局限于解决非负权的最短路径问题,对于带负权的图就力 ...
- Dijkstra算法与Bellman - Ford算法示例(源自网上大牛的博客)【图论】
题意:题目大意:有N个点,给出从a点到b点的距离,当然a和b是互相可以抵达的,问从1到n的最短距离 poj2387 Description Bessie is out in the field and ...
- poj1860 bellman—ford队列优化 Currency Exchange
Currency Exchange Time Limit: 1000MS Memory Limit: 30000K Total Submissions: 22123 Accepted: 799 ...
- 图论——最短路径 Dijkstra算法、Floyd算法
1.弗洛伊德算法(Floyd) 弗洛伊算法核心就是三重循环,M [ j ] [ k ] 表示从 j 到 k 的路径,而 i 表示当前 j 到 k 可以借助的点:红色部分表示,如果 j 到 i ,i 到 ...
- uva 558 - Wormholes(Bellman Ford判断负环)
题目链接:558 - Wormholes 题目大意:给出n和m,表示有n个点,然后给出m条边,然后判断给出的有向图中是否存在负环. 解题思路:利用Bellman Ford算法,若进行第n次松弛时,还能 ...
- 图论算法——最短路径Dijkstra,Floyd,Bellman Ford
算法名称 适用范围 算法过程 Dijkstra 无负权 从s开始,选择尚未完成的点中,distance最小的点,对其所有边进行松弛:直到所有结点都已完成 Bellman-Ford 可用有负权 依次对所 ...
- 算法学习笔记(三) 最短路 Dijkstra 和 Floyd 算法
图论中一个经典问题就是求最短路.最为基础和最为经典的算法莫过于 Dijkstra 和 Floyd 算法,一个是贪心算法,一个是动态规划.这也是算法中的两大经典代表.用一个简单图在纸上一步一步演算,也是 ...
- 数据结构与算法--最短路径之Bellman算法、SPFA算法
数据结构与算法--最短路径之Bellman算法.SPFA算法 除了Floyd算法,另外一个使用广泛且可以处理负权边的是Bellman-Ford算法. Bellman-Ford算法 假设某个图有V个顶点 ...
- 【hdu 2544最短路】【Dijkstra算法模板题】
Dijkstra算法 分析 Dijkstra算法适用于边权为正的情况.它可用于计算正权图上的单源最短路( Single-Source Shortest Paths, SSSP) , 即从单个源点出发, ...
随机推荐
- mysql <-> sqlite
在做程序时,sqlite数据很方便.用mysql数据导出到sqlite的步骤:(用csv文件过渡) ------------------------------- 先导出到csv文件 ------ ...
- Zero Requiem
“最后是在游行.暴君鲁路修高居王座,两侧列着所有反对者的代表:黑色骑士团.黎星刻.原圆桌骑士名列第三的吉诺,以及一身女囚装的娜娜丽,他们都即将被公开处死.尤菲米娅在第一次“特别行政区•日本”成立仪式上 ...
- 创建sa账号
①以windows身份验证的方式默认登陆 ②选择安全性下的登录名中的sa账号,右键选择属性,进行相关项的设置 ③将sa账号的状态中对应的登录项由之前的禁用,改为已启用 ④将sa对应的密码进行修改为自己 ...
- Karma 4 - Karma 集成 Webpack 进行单元测试
可以将 karma 与 webpack 结合起来,自动化整个单元测试过程. 配置环境 1. 首先根据 1 完成基本的 karma 测试环境. 2. 安装 webpack 和 webpack 使用的 l ...
- 剑指Offer:面试题27——二叉搜索树与双向链表(java实现)
问题描述: 输入一棵二叉搜索树,将该二叉搜索树转换成一个排序的双向链表.要求不能创建任何新的结点,只能调整树中结点指针的指向. 思路: 将树分为三部分:左子树,根结点,右子树. 1.我们要把根结点与左 ...
- QueryRunner(common-dbutils.jar)
QueryRunner update方法:* int update(String sql, Object... params) --> 可执行增.删.改语句* int update(Connec ...
- express 4 中 session的处理(仅为博主笔记)
1.app.js var express = require('express') var app = express();var routers = require('./router/index' ...
- scrollWidth的巧妙运用
再了无生趣的工作也是能够帮助我们提高的~ 最近工作比较无聊,于是就想到了写一个滚动条插件,在借鉴了mCustomerScrollbar这个组件之后我简单的写了一个类似的,当然,相比于它的2000多行代 ...
- 我要崩溃了,要解出这么一段js代码背后的东西,这真是一坨啊,别被高度欺骗了,他还有宽度!!!!!试着按下方向右键
一坨js代码: function s_gi(un, pg, ss) { var c = "s.version='H.26';s.an=s_an;s.logDebug=function(m){ ...
- java获取当前执行文件的路径
需要知道执行jar包时,jar包所在的路径. 开始使用了 p.getClass().getResource("/").getPath(); 结果在IDE里面使用是好的,但是在命令行 ...