最短路算法 (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] := 0
       else distance[v] := infinity
       predecessor[v] := null

   // 步骤2:重复对每一条边进行松弛操作
   for i from 1 to size(vertices)-1:
       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 "图包含了负权环"

POJ 3259

题意: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+7;
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 = 2; i <= field; i++) dis[i] = M;     ///初始化操作;
    for(int i = 1; i <  field; i++){                ///松弛操作;
        for(int j = 1; 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 = 1; 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 = 0;
        scanf("%d%d%d", &field, &path, &wormhole);
        for(int i = 0; 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 = 0; 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 0;
}

POj 1860

题意: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+7;
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 = 0; i <= n; i++){
        sign = 0;
        for(int j = 1; 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 = 1;
        }
        if(!sign)
            break;
    }
    for(int j = 1; 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 = 0;
        for(int i = 0; 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 0;
}

时间: 2024-10-05 03:41:15

最短路算法 (bellman-Ford算法)的相关文章

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

Bellman - Ford 算法: 一:基本算法 对于单源最短路径问题,上一篇文章中介绍了 Dijkstra 算法,但是由于 Dijkstra 算法局限于解决非负权的最短路径问题,对于带负权的图就力不从心了,而Bellman - Ford算法可以解决这种问题. Bellman - Ford 算法可以处理路径权值为负数时的单源最短路径问题.设想可以从图中找到一个环路且这个环路中所有路径的权值之和为负.那么通过这个环路,环路中任意两点的最短路径就可以无穷小下去.如果不处理这个负环路,程序就会永远运

Bellman—Ford算法思想

---恢复内容开始--- Bellman—Ford算法能在更普遍的情况下(存在负权边)解决单源点最短路径问题.对于给定的带权(有向或无向)图G=(V,E),其源点为s,加权函数w是边集E的映射.对图G运行Bellman—Ford算法的结果是一个布尔值,表明图中是否存在着一个从源点s可达的负权回路.若存在负权回路,单源点最短路径问题无解:若不存在这样的回路,算法将给出从源点s到图G的任意顶点v的最短路径值d[v] Bellman—Ford算法流程 分为三个阶段: (1)初始化:将除源点外的所有顶点

poj 3259 Wormholes (BELLman—FOrd算法)(邻接矩阵表示)

http://poj.org/problem?id=3259 之前一开始 ,没做出来,搁置了好几天才看见bug所在.所以今天a掉了 ,把代码贴出来,这个使用邻接矩阵表示的 ,下一篇用邻接表可以提高效率. #include<iostream> #include<queue> #include<stdio.h> #include<string.h> using namespace std; const int INF=600; int G[INF][INF];

最短路径——Bellman Ford算法(C++)

源代码: #include<cstdio>#include<cstring>int m(1),n,k,i[1001],x[1001],y[1001],f[1001];int main(){ scanf("%d%d",&n,&k); for (int a=1;a<=n;a++) for (int b=1;b<=n;b++) { scanf("%d",&i[m]); if (i[m]!=-1) { x[m]=a

POJ 1860 Currency Exchange (Bellman ford)

Currency Exchange Time Limit: 1000MS   Memory Limit: 30000K Total Submissions: 22405   Accepted: 8095 Description Several currency exchange points are working in our city. Let us suppose that each point specializes in two particular currencies and pe

bellman-ford算法

给定图G(V, E)(其中V.E分别为图G的顶点集与边集),源点s, 数组Distant[i]记录从源点s到顶点i的路径长度,初始化数组Distant[n]为, Distant[s]为0: 以下操作循环执行至多n-1次,n为顶点数:对于每一条边e(u, v),如果Distant[u] + w(u, v) < Distant[v],则另Distant[v] = Distant[u]+w(u, v).w(u, v)为边e(u,v)的权值:若上述操作没有对Distant进行更新,说明最短路径已经查找完

关于最短路的几个算法

关于最短路的几个算法有Dijkstra,Bellman-Ford,Floyd Dijkstra: Dijkstra适用于边权为正的情况,从单个源点出发,到其他所有结点的最短路 算法的核心是用已经知道的结点 i 的距离 d[i] 去更新和这个结点相连的其他结点的距离 void Dijkstra() { memset(vis,0,sizeof(vis)); //vis数组表示结点是否被访问 memset(d,INF,sizeof(d)); //d数组表示到结点的距离 d[s]=0; //将起点的距离

最短路算法 :Bellman-ford算法 &amp; Dijkstra算法 &amp; floyd算法 &amp; SPFA算法 详解

 本人QQ :2319411771   邮箱 : [email protected] 若您发现本文有什么错误,请联系我,我会及时改正的,谢谢您的合作! 本文为原创文章,转载请注明出处 本文链接   :http://www.cnblogs.com/Yan-C/p/3916281.html . 很早就想写一下最短路的总结了,但是一直懒,就没有写,这几天又在看最短路,岁没什么长进,但还是加深了点理解. 于是就想写一个大点的总结,要写一个全的. 在本文中因为邻接表在比赛中不如前向星好写,而且前向星效率并

图论之最短路01——最短路矩阵(FLOYD)算法

%======================================================== %最短路矩阵算法,FLOYD算法 %针对性:方案预算,能求出所有点之间的最短路(最小费用等) %======================================================== function D=zuiduanjulijuzhen(quanzhijuzhen) n=length(quanzhijuzhen); D=quanzhijuzhen; m

[poj2449]Remmarguts&#39; Date(K短路模板题,A*算法)

解题关键:k短路模板题,A*算法解决. #include<cstdio> #include<cstring> #include<algorithm> #include<cstdlib> #include<iostream> #include<cmath> #include<queue> using namespace std; typedef long long ll; const int N=1e3+10; const