• 最短路-Bellmanford


    简介:

    给定一个图和一个源点,求源点到其余点的最短路径,图中有可能存在负权边。

    算法步骤

    1.初始化:将除源点外的所有顶点的最短距离估计值 dist[v] ← +∞, dist[s] ←0; 
    2.迭代求解:反复对边集E中的每条边进行松弛操作,使得顶点集V中的每个顶点v的最短距离估计值逐步逼近其最短距离;(运行|v|-1次) 
    3.检验负权回路:判断边集E中的每一条边的两个端点是否收敛。如果存在未收敛的顶点,则算法返回false,表明问题无解;否则算法返回true,并且从源点可达的顶点v的最短距离保存在 dist[v]中。

    如果存在从源点可达的权为负的回路。则 应为无法收敛而导致不能求出最短路径。

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

     

    第二次遍历后,点B的值变为3,点C变为6,点A变为-4。正是因为有一条负边在回路中,导致每次遍历后,各个点的值不断变小。所以这是无限循环的。

    #include<iostream>
    #include<cstdio>
    using namespace std;
    #define MAX 0x3f3f3f3f
    #define N 1010
    int nodenum, edgenum, original; //点,边,起点
    typedef struct Edge //
    {
        int u, v;
        int cost;
    } Edge;
    Edge edge[N];
    int dis[N], pre[N];
    bool Bellman_Ford()
    {
        int ok;
        for(int i = 1; i <= nodenum; ++i) //初始化,起点本身赋值为0,其余赋值为最大
            dis[i] = (i == original ? 0 : MAX);
        for(int i = 1; i <= nodenum - 1; ++i)
        {
            ok=1;
            for(int j = 1; j <= edgenum; ++j)
                if(dis[edge[j].v] > dis[edge[j].u] + edge[j].cost) //松弛(顺序一定不能反)
                {
                    dis[edge[j].v] = dis[edge[j].u] + edge[j].cost;
                    pre[edge[j].v] = edge[j].u;//这里用来存储路径
                    ok=0;
                }
            if(ok==1) //优化这里,如果这趟没跟新任何节点就可以直接退出了。
                break;
        }
        bool flag = 1; //判断是否含有负权回路
        for(int i = 1; i <= edgenum; ++i)
            if(dis[edge[i].v] > dis[edge[i].u] + edge[i].cost)
            {
                flag = 0;
                break;
            }
        return flag;
    }
    void print_path(int root) //打印最短路的路径(反向)
    {
        while(root != pre[root]) //前驱
        {
            printf("%d-->", root);
            root = pre[root];
        }
        if(root == pre[root])
            printf("%d
    ", root);
    }
    
    int main()
    {
        scanf("%d%d%d", &nodenum, &edgenum, &original);//输入点边起点,一般起点规定为1
        pre[original] = original;//为了输出最短路用的,前驱为本身
        for(int i = 1; i <= edgenum; ++i)
        {
            scanf("%d%d%d", &edge[i].u, &edge[i].v, &edge[i].cost);//有向图
        }
        if(Bellman_Ford())//如果没有负权
            for(int i = 1; i <= nodenum; ++i) //每个点最短路
            {
                printf("%d
    ", dis[i]);
                printf("Path:");
                print_path(i);
            }
        else
            printf("have negative circle
    ");
        return 0;
    }
    宝剑锋从磨砺出 梅花香自苦寒来
  • 相关阅读:
    Java String 字符串操作小结
    找到一篇关于 Oracle 全文检索实践 的文章
    Java中Array与ArrayList的主要区别
    Java使用Array类创建多维数组
    [例] 用MappedByteBuffer更新文件内容
    java nio 之MappedByteBuffer
    Java.util.Properties类
    Oracle外连接与条件的组合
    Oracle 树形SQL语句,SYS_CONNECT_BY_PATH 函数
    SQL Connect By 的例子
  • 原文地址:https://www.cnblogs.com/GHzcx/p/9148116.html
Copyright © 2020-2023  润新知