AcWing 853. 有边数限制的最短路

题目传送门

一、(bellman-ford)算法

算法思路

for n次 //迭代n次(n个结点)
  for 所有边    //a,b,w 表示存在一条a->b 的边,权重是 w
     dist[b]=min(dist[b],dist[a]+w)

和迪杰斯特拉算法基本思想是一致的:通过一个一个的引入其它结点,让两点之间的距离更短。数学上可以证明,执行完(n)次后,最终可以得到(asim b)的最短路径。

二、要点总结

  • (bellman-ford)可以处理负权边,而(Dijkstra)只能处理正权边。

  • (bellman-ford)算法可以处理负权回路,因为它求得的最短路是有限制的,是限制了边数的,这样不会永久的走下去,会得到一个解;

  • 有负权回路的话,最短路是不一定存在的。为什么是不一定,可以看图(1)和图(2).

    图$1$描述了一直走下去一直小,那么,最短路径就是负无穷,不存在最短路径。
    图$2$描述了虽然有负权回路,但由于此负权回路不在$1$~$n$的路线中,不影响最短路,所以存在最短路径。
  • (bellman-ford)是可以找负环的,但时间复杂度比较高,一般不用它来找负环。(bellman-ford)能干的事,(SPFA)都能干,而且时间复杂度比(bellman-ford)要低。

  • (SPFA)算法各方面优于该算法,但是在碰到限制了最短路径长度时就只能用(bellman-ford)了,此时直接把(n)重循环改成(k)次循环即可

  • 有边数限制的最短路径
    (bellman-ford)算法擅长解决有边数限制的最短路问题,其它算法没有这个功能!
    比个现实中的场景:旅游(n)个城市,(1)->(n)没有直达的飞机,需要经其它的城市进行中转,票价就是中转的机票票价之和,每次中转都会让人的心情不爽一点,也就是不能超过(k)次中转。这个场景因为
    限制了边数的数量上限(k),就只能用(bellman-ford)算法。

三、C++ 代码

#include <bits/stdc++.h>

using namespace std;
const int INF = 0x3f3f3f3f;
const int N = 510;   //结点数
const int M = 10010; //边数

//存边的方式
struct Edge {
    //三个整数a,b,c,表示存在一条从点a到点b的有向边,边长为c。
    int a, b, c;
} edges[M]; //边的数组

int n, m; //n个结点,m条边
int k;    //表示从1号点到n号点的最多经过k条边的最短距离
int dist[N];//距离数组
int backup[N];//备份数组

// 输出一个整数,表示从1号点到n号点的最多经过k条边的最短距离
void bellman_ford() {
    // 初始化为无穷大
    memset(dist, 0x3f, sizeof dist);
    dist[1] = 0; //1点节点到自己的长度是0

    //循环k次,因为只有k次机会
    for (int i = 1; i <= k; i++) {
        //上一次的结果(备份出来)
        //为了在一次迭代中防止更新多条边的情况,需要备份出来
        memcpy(backup, dist, sizeof dist);//防止发生串联,只用上一次迭代的结果就不会发生串联。
        //循环所有边
        for (int j = 0; j < m; j++) {
            Edge e = edges[j];
            dist[e.b] = min(dist[e.b], backup[e.a] + e.c);
        }
    }
}

int main() {
    //读入优化
    ios::sync_with_stdio(false);
    //读入数据
    cin >> n >> m >> k;
    for (int i = 0; i < m; i++) {
        //三个整数a,b,c,表示存在一条从点a到点b的有向边,边长为c。
        int a, b, c;
        cin >> a >> b >> c;
        edges[i] = {a, b, c};
    }
    //调用bellman_Ford算法
    bellman_ford();
    //输出结果
    if (dist[n] > INF / 2) puts("impossible");
    else printf("%d
", dist[n]);
    return 0;
}
原文地址:https://www.cnblogs.com/littlehb/p/15319764.html