码迷,mamicode.com
首页 > 编程语言 > 详细

最短路算法 (bellman-Ford算法)

时间:2016-04-13 08:32:36      阅读:503      评论:0      收藏:0      [点我收藏+]

标签:

贝尔曼-福特算法迪科斯彻算法类似,都以松弛操作为基础,即估计的最短路径值渐渐地被更加准确的值替代,直至得到最优解。在两个算法中,计算时每个边之间的估计距离值都比真实值大,并且被新找到路径的最小长度替代。 然而,迪科斯彻算法以贪心法选取未被处理的具有最小权值的节点,然后对其的出边进行松弛操作;而贝尔曼-福特算法简单地对所有边进行松弛操作,共|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 "图包含了负权环"
View Code

 

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;
}
View Code

 

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;
}
View Code

 

最短路算法 (bellman-Ford算法)

标签:

原文地址:http://www.cnblogs.com/yoyo-sincerely/p/5379888.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!