zoukankan      html  css  js  c++  java
  • 最短路

    http://acm.sdut.edu.cn/sdutoj/problem.php?action=showproblem&problemid=2894

    谈一下对贝尔曼福特的认识(参考别人的)

    BF是对边进行操作,dijkstra 是对点进行操作,N个顶点的最短路最多是N-1条边,所以需要循环N-1次

    1.初始化

    2.迭代求解:反复对边集中的每条边进行松弛操作,使得顶点集v中的每个顶点vde最短距离逐步逼近其最短距离,运行v-1次

    3:检验负权回路:判断边集中的每一条边的两个端点是否收敛,如果存在未瘦脸的顶点,则返回false,表明问题无解,否则算法返回true,并且从源点可达的顶点v的最短距离保存在的d【v】中。

     

     

    4描述性证明编辑

     

    首先指出,图的任意一条最短路径既不能包含负权回路,也不会包含正权回路,因此它最多包含|v|-1条边。

     

    其次,从源点s可达的所有顶点如果 存在最短路径,则这些最短路径构成一个以s为根的最短路径树。Bellman-Ford算法的迭代松弛操作,实际上就是按顶点距离s的层次,逐层生成这棵最短路径树的过程。

     

    在对每条边进行第1遍松弛的时候,生成了从s出发,层次至多为1的那些树枝。也就是说,找到了与s至多有1条边相联的那些顶点的最短路径;对每条边进行第2遍松弛的时候,生成了第2层次的树枝,就是说找到了经过2条边相连的那些顶点的最短路径……。因为最短路径最多只包含|v|-1 条边,所以,只需要循环|v|-1 次。

     

    每实施一次松弛操作最短路径树上就会有一层顶点达到其最短距离,此后这层顶点的最短距离值就会一直保持不变,不再受后续松弛操作的影响。(但是,每次还要判断松弛,这里浪费了大量的时间,怎么优化?单纯的优化是否可行?)

     

    注意:上述只对正权图有效。如果存在负权不一定第i次就能确定最短路,且与边的顺序有关。

     

    如果没有负权回路,由于最短路径树的高度最多只能是|v|-1,所以最多经过|v|-1遍松弛操作后,所有从s可达的顶点必将求出最短距离。如果 d[v]仍保持 +∞,则表明从s到v不可达。

     

    如果有负权回路,那么第 |v| 遍松弛操作仍然会成功,这时,负权回路上的顶点不会收敛。[1]

     

     

     

     

     

     
    Bellman-Ford算法可以大致分为三个部分
    第一,初始化所有点。每一个点保存一个值,表示从原点到达这个点的距离,将原点的值设为0,其它的点的值设为无穷大(表示不可达)。
    第二,进行循环,循环下标为从1到n-1(n等于图中点的个数)。在循环内部,遍历所有的边,进行松弛计算。
    第三,遍历途中所有的边(edge(u,v)),判断是否存在这样情况:
    d(v) > d (u) + w(u,v)
    则返回false,表示途中存在从源点可达的权为负的回路。
     
    之所以需要第三部分的原因,是因为,如果存在从源点可达的权为负的回路。则 应为无法收敛而导致不能求出最短路径。
    考虑如下的图:
     

     

    经过第一次遍历后,点B的值变为5,点C的值变为8,这时,注意权重为-10的边,这条边的存在,导致点A的值变为-2。(8+ -10=-2)
     
     

     

    第二次遍历后,点B的值变为3,点C变为6,点A变为-4。正是因为有一条负边在回路中,导致每次遍历后,各个点的值不断变小。
     
    在回过来看一下bellman-ford算法的第三部分,遍历所有边,检查是否存在d(v) > d (u) + w(u,v)。因为第二部分循环的次数是定长的,所以如果存在无法收敛的情况,则肯定能够在第三部分中检查出来。比如
     

     

    此时,点A的值为-2,点B的值为5,边AB的权重为5,5 > -2 + 5. 检查出来这条边没有收敛。
     
    所以,Bellman-Ford算法可以解决图中有权为负数的边的单源最短路径问。

     

     

    http://blog.csdn.net/u012860063/article/details/24492003

     

    // BF  贝尔曼福特代码模板,学习
    #include <stdio.h>
    #include <string.h>
    #define INF 999999
    struct node
    {
        int u,v,w;
    }q[4000002];
    int dis[500002];
    int t = 0;
    int n,m;
    int s,e;
    int u,v,w;
    int flag;
    void add(int u,int v,int w)
    {
        q[t].u = u;
        q[t].v = v;
        q[t++].w = w;
    }
    void BF()
    {
        int i,j;
        for(i = 0;i<=n;i++)
        {
            dis[i] = INF;
        }
        dis[s] = 0;
        for(i = 1;i<=n-1;i++)
        {
            flag = 0;
            for(j = 0;j<t;j++)
            {
                if(dis[q[j].v]>dis[q[j].u] + q[j].w)
                {
                    dis[q[j].v] = dis[q[j].u] + q[j].w;
                    flag = 1;
                }
            }
            if(flag == 0)
            break;
        }
        printf("%d
    ",dis[e]);
    }
    int main()
    {
        int i = 0;
        while(scanf("%d%d",&n,&m)!=EOF)
        {
            for(i = 0;i<m;i++)
            {
                scanf("%d%d%d",&u,&v,&w);
                add(u,v,w);
                add(v,u,w);
            }
            scanf("%d%d",&s,&e);
            BF();
        }
        return 0;
    }
  • 相关阅读:
    HDU3336 Count the string —— KMP next数组
    CodeForces
    51Nod 1627 瞬间移动 —— 组合数学
    51Nod 1158 全是1的最大子矩阵 —— 预处理 + 暴力枚举 or 单调栈
    51Nod 1225 余数之和 —— 分区枚举
    51Nod 1084 矩阵取数问题 V2 —— 最小费用最大流 or 多线程DP
    51Nod 机器人走方格 V3 —— 卡特兰数、Lucas定理
    51Nod XOR key —— 区间最大异或值 可持久化字典树
    HDU4825 Xor Sum —— Trie树
    51Nod 1515 明辨是非 —— 并查集 + 启发式合并
  • 原文地址:https://www.cnblogs.com/yangyongqian/p/3887072.html
Copyright © 2011-2022 走看看