ACwing 853. 有边数限制的最短路(Bellman-ford)

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

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

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

输入格式

第一行包含三个整数 n,m,k。

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

输出格式

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

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

数据范围

1≤n,k≤500
1≤m≤10000,
任意边长的绝对值不超过 10000

输入样例:

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

输出样例:

3

思路分析:对于负权问题一般有两种解决方案一种是bellman-ford另一种是SPFA,本题存在负权但是不能使用spfa,原因如下

  1. 存在负环(SPFA无法解决负环)
  2. 规定了走k步

所以只能使用bellman-ford算法。

注意事项:

  1. 要有一个备份数组backdis,(保存上一轮循环更新完后1到其他点的最短路) 使用bellman-ford更新时,需要走k步,每走完一步都需要更新到其他点的最短路,更新的过程中务必保证使用backdis数组更新dis数组,只有这样才能保证一轮循环是仅仅走了一步(思考一下)。
  2. 因为存在负权,所以dis[n]也有可能被更新,所以判断不能到达的条件不能是dis[n]==0x3f3f3f3f。如下图所示

初始状态,假设∞=0x3f3f3f3f

走了k步(假设k=1)后

可以发现存在这样一种情况,dis[n]!=0x3f3f3f3f,所以最终不可达判断条件不能是dis[n]==0x3f3f3f3f

可以把判断条件改成dis[n]==0x3f3f3f3f/2

#include<bits/stdc++.h>
#define inf 0x3f3f3f3f
using namespace std;
const int maxn = 10010;
int dis[510],backdis[510];
struct node
{
    int u,v,w;
}e[maxn];
void bellman_ford(int k,int n,int m)
{
    memset(dis,inf,sizeof dis);
    dis[1]=0;
    for(int i = 0;i<k;i++)
    {
        memcpy(backdis,dis,sizeof dis);
        for(int j = 0;j<m;j++)
        {
            if(dis[e[j].v]>backdis[e[j].u]+e[j].w)
            {
                dis[e[j].v]=backdis[e[j].u]+e[j].w;
            }
        }

    }
    if(dis[n]>inf/2) cout<<"impossible"<<endl;
    else cout<<dis[n]<<endl;
}
int main()
{
    int n,m,k;
    cin>>n>>m>>k;
    for(int i = 0;i<m;i++)
    {
        scanf("%d %d %d",&e[i].u,&e[i].v,&e[i].w);
    }
    bellman_ford(k,n,m);
    return 0;
}

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值