• bellman_ford


    bellman_ford(贝尔曼-福特)算法:因为dijkstra算法不能处理带负权边的图,这时候就可以利用bellman_ford算法。( 设想从我们可以从图中找到一个环路(即从v出发,经过若干个点之后又回到v)且这个环路中所有路径的权值之和为负。那么通过这个环路,环路中任意两点的最 短路径就可以无穷小下去。如果不处理这个负环路,程序就会永远运行下去。 而Bellman-Ford算法具有分辨这种负环路的能力)

    时间复杂度:O(ne)——n是点数,e是边数。如果是邻接阵的话应该就是O(n^3).


    联系:可以优化成SPFA。可以用来写差分约束

    实现过程:设G为加权有向图 V是所有结点的集合 E是所有路径的集合 S表示源点 n表示V中所有结点的数目 weight(u,v)表示从结点u  到结点v的路径的权值。 Distanz(v)表示从源点s出发到结点v的最短路径的距离,(或者说是从s到v所有的路径中权值的最小值)。Predecessor(v)表示节点 v的父结点

    在Bellman-Ford算法结束之后,可以输出,G是不是包含一个负环路。如果G不包含负环路,那么Distanz就存储了从s出发到所有结点的距离。

    Bellman-Ford算法的伪代码如下:
    ========================================
    01 for 每一个结点v 属于 V
    02 Distanz(v) := 无穷大, Predecessor(v) := null
    03 Distanz(s) := 0,Predecessor(s):= null;

    04 循环 n-1 次
    05     for 每一条路径 (u,v)属于 E
    06         if Distanz(u) + weight(u,v) < Distanz(v)
    07         then
    08            Distanz(v) := Distanz(u) + weight(u,v)
    09            Predecessor(v) := u;

    10 for 每一条路径 (u,v)属于 E
    11     if Distanz(u) + weight(u,v) < Distanz(v)
    12     then
    13       中止程序并且返回 “找到负循环”
    14 返回
    ==============================================

    下面是我用bellman_ford 和静态邻接表写的hdu2544

    代码
    #include <iostream>
    using namespace std;
    const long point_maxn = 105;
    const long edge_maxn = 10005;
    const long lmaxn = 1000000000;
    int n;
    int m;
    struct node
    {
    int v;
    int w;
    int next;
    }edge[edge_maxn];
    int pre[point_maxn];
    int dirs[point_maxn];
    void Init()
    {
    int i,j;
    int a,b,c;
    int Index = 1;
    memset(pre,
    -1,sizeof(pre));
    for(i=0;i<m;i++)
    {
    int flag;
    scanf(
    "%d%d%d",&a,&b,&c);
    for(flag=0,j=pre[a];j!=-1;j=edge[j].next)
    {
    if(edge[j].v == b)
    {
    if(edge[j].w > c)
    {
    edge[j].w
    = c;
    }
    flag
    = 1;
    break;
    }
    }
    if(flag == 1)
    continue;
    edge[Index].v
    = b;
    edge[Index].w
    = c;
    edge[Index].next
    = pre[a];
    pre[a]
    = Index++;
    swap(a,b);
    for(flag=0,j=pre[a];j!=-1;j=edge[j].next)
    {
    if(edge[j].v == b)
    {
    if(edge[j].w > c)
    {
    edge[j].w
    = c;
    }
    break;
    }
    }
    edge[Index].v
    = b;
    edge[Index].w
    = c;
    edge[Index].next
    = pre[a];
    pre[a]
    = Index++;
    }
    }
    int bellman_ford()
    {
    int i,j,k;
    fill(dirs,dirs
    +point_maxn,lmaxn);
    int start = 1;
    int end = n;
    dirs[start]
    = 0;
    for(i=0;i<n-1;i++)
    {
    for(j=1;j<=n;j++)
    {
    for(k=pre[j];k!=-1;k=edge[k].next)
    {
    int s = j;
    int e = edge[k].v;
    if(dirs[e] > dirs[s] + edge[k].w)
    {
    dirs[e]
    = dirs[s] + edge[k].w;
    }
    }
    }
    }
    for(j=1;j<=n;j++)
    {
    for(k=pre[j];k!=-1;k=edge[k].next)
    {
    int s = j;
    int e= edge[k].v;
    if(dirs[e] > dirs[s] + edge[k].w)
    {
    return 0;
    }
    }
    }
    return 1;
    }
    void print()
    {
    if(!bellman_ford())
    {
    printf(
    "-1\n");
    }
    else
    {
    printf(
    "%d\n",dirs[n]);
    }
    }
    int main()
    {
    while(scanf("%d%d",&n,&m)!=EOF && (n!=0 || m!=0))
    {
    Init();
    print();
    }
    return 0;
    }

  • 相关阅读:
    夺命雷公狗---Thinkphp----16之首页的完成及全站的完成
    夺命雷公狗---Thinkphp----15之遍历出来的栏目页的完成
    夺命雷公狗---Thinkphp----14之前台的首页完善
    夺命雷公狗-----tp中遇到数据乘积的问题的遇见
    夺命雷公狗---Thinkphp----13之前台的头尾分离和导航分离
    夺命雷公狗---Thinkphp----12之文章的增删改查(图片上传和关联查询)
    夺命雷公狗TP下关联查询
    夺命雷公狗---Thinkphp----11之管理员的增删改查的完善
    夺命雷公狗---Thinkphp----10之后台登录.注销一条龙
    夺命雷公狗---Thinkphp----9之中间层的创建,防止跨目录访问
  • 原文地址:https://www.cnblogs.com/silencExplode/p/1876783.html
Copyright © 2020-2023  润新知