bellman - ford算法

给定一个 \(n\) 个点 \(m\) 条边的有向图,图中可能存在重边和自环, 边权可能为负数

请你求出从 \(1\) 号点到 \(n\) 号点的最多经过 \(k\) 条边的最短距离,如果无法从 \(1\) 号点走到 \(n\) 号点,输出 impossible

注意:图中可能 存在负权回路

输入格式

第一行包含三个整数 \(n,m,k\)

接下来 \(m\) 行,每行包含三个整数 \(x,y,z\),表示存在一条从点 \(x\) 到点 \(y\) 的有向边,边长为 \(z\)

点的编号为 \(1 \sim n\)

输出格式

输出一个整数,表示从 \(1\) 号点到 \(n\) 号点的最多经过 \(k\) 条边的最短距离。

如果不存在满足条件的路径,则输出 impossible

数据范围

\(1 \le n,k \le 500\),
\(1 \le m \le 10000\),
\(1 \le x,y \le n\)
任意边长的绝对值不超过 \(10000\)

输入样例:

3 3 1
1 2 1
2 3 1
1 3 3

输出样例:

3

分析

该算法可以处理边权为负值的情况,bellman - ford算法擅长解决有边数限制的最短路问题
时间复杂度 O(nm)其中n为点数,m为边数,该算法主要是松弛操作,可以参考以下视频。

代码实现

#include <cstring>
#include <iostream>
#include <algorithm>

using namespace std;

const int N = 510, M = 10010;

struct Edge
{
    int a, b, c;
}edges[M];

int n, m, k;
int dist[N];
int last[N];

void bellman_ford()
{
    memset(dist, 0x3f, sizeof dist);

    dist[1] = 0;
    for (int i = 0; i < k; i ++ )
    {
        memcpy(last, dist, sizeof dist);
        for (int j = 0; j < m; j ++ )
        {
            auto e = edges[j];
            dist[e.b] = min(dist[e.b], last[e.a] + e.c);
        }
    }
}

int main()
{
    scanf("%d%d%d", &n, &m, &k);

    for (int i = 0; i < m; i ++ )
    {
        int a, b, c;
        scanf("%d%d%d", &a, &b, &c);
        edges[i] = {a, b, c};
    }

    bellman_ford();

    if (dist[n] > 0x3f3f3f3f / 2) puts("impossible");
    else printf("%d\n", dist[n]);

    return 0;
}
//https://www.acwing.com/activity/content/code/content/48523/
//来源:AcWing

posted @ 2023-08-30 11:45  LongDz  阅读(39)  评论(0)    收藏  举报