【ACWing】853. 有边数限制的最短路

题目地址:

https://www.acwing.com/problem/content/855/

给定一个 n n n个点 m m m条边的有向图,图中可能存在重边和自环,边权可能为负数。请你求出从 1 1 1号点到 n n n号点的最多经过 k k k条边的最短距离,如果无法从 1 1 1号点走到 n n n号点,输出impossible

输入格式:
第一行包含三个整数 n n n m m m k k k。接下来 m m m行,每行包含三个整数 x x x y y y z z z,表示存在一条从点 x x x到点 y y y的有向边,边长为 z z z

输出格式:
输出一个整数,表示从 1 1 1号点到 n n n号点的最多经过 k k k条边的最短距离。如果不存在满足条件的路径,则输出impossible

数据范围:
1 ≤ n , k ≤ 500 1\le n,k\le 500 1n,k500
1 ≤ m ≤ 10000 1\le m\le 10000 1m10000
0 ≤ ∣ e ∣ ≤ 10000 0\le |e|\le 10000 0e10000
e e e是边长

有边数限制的最短路只能用Bellman-Ford算法来做。它的算法步骤是,循环 k k k次,每次循环内部,再循环每条边,用这条边来尝试更新这条边入点的最短路。注意,在进行内部循环之前,要对dist数组做一个备份,以防dist数组是以当前内循环已经更新过的数值来更新的(外循环实际上是限制了最多经过多少条边。如果不备份的话,内层循环算出来的最短路有可能是超过外层循环的限制边数的)。这个算法的思路其实是动态规划,设 f [ k ] [ x ] f[k][x] f[k][x]是从 1 1 1号点走不超过 k k k条边走到 x x x的所有路径里的最短路,初始条件是 f [ 0 ] [ 1 ] = 0 f[0][1]=0 f[0][1]=0,按照 x x x的上一个点是谁可以做分类,则有: f [ k ] [ x ] = min ⁡ y → x { f [ k − 1 ] [ y ] + d [ y ] [ x ] } f[k][x]=\min_{y\to x}\{f[k-1][y]+d[y][x]\} f[k][x]=yxmin{f[k1][y]+d[y][x]}每轮循环枚举所有的边,最后要求的就是 f [ k ] [ n ] f[k][n] f[k][n]。代码如下:

#include <iostream>
#include <cstring>
using namespace std;

const int N = 510, M = 10010, INF = 0x3f3f3f3f;
int n, m, k;
struct Edge {
  int u, v, w;
} e[M];
int dist[2][N];

int bellman_ford() {
  memset(dist, 0x3f, sizeof dist);
  dist[0][1] = dist[1][1] = 0;

  for (int i = 1; i <= k; i++)
    for (int j = 1; j <= m; j++) {
      int u = e[j].u, v = e[j].v, w = e[j].w;
      dist[i & 1][v] = min(dist[i & 1][v], dist[i - 1 & 1][u] + w);
    }

  if (dist[k & 1][n] > INF / 2) return INF;
  else return dist[k & 1][n];
}

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

  for (int i = 1; i <= m; i++) {
    int u, v, w;
    scanf("%d%d%d", &u, &v, &w);
    e[i] = {u, v, w};
  }

  int res = bellman_ford();

  res == INF ? puts("impossible") : printf("%d\n", res);
}

时间复杂度 O ( n m ) O(nm) O(nm),空间 O ( n + m ) O(n+m) O(n+m)

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值