AcWing 853. 有边数限制的最短路 - Bellman-ford算法

为什么Dijkstra算法不能使用在含负权的图中?对Bellman—ford算法的介绍等,下面这篇题解讲得很不错。

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

#include<iostream>
#include<cstring>
#include<algorithm>
using namespace std;
const int N = 510;//点
const int M = 10010;//边
//用结构体存储边
struct Edge
{
    int a,b,c;
}edges[M];

int n,m,k;
int dist[N];
int last[N];//每次迭代存储的dist数组备份

void bellman_ford()
{
    memset(dist,0x3f,sizeof dist);
    dist[1] = 0;
    
    //不超过k条边我们就设定循环最大值为k
    for(int i=0;i<k;i++)
    {
        //每次迭代我们需要备份一次dist数组,目的是保证每次迭代只更新长度为1
        //不会出现更新了一个点,又用一个点去更新别的点,串联不已
        memcpy(last,dist,sizeof dist);
        //枚举edges里面存的所有边,可以更新的,我们就更新
        for(int j = 0;j<m;j++)
        {
            auto e = edges[j];
            //注意这里一定要用last数组去更新
            dist[e.b] = min(dist[e.b],last[e.a]+e.c);
        }
    }
}
int main()
{
    cin>>n>>m>>k;
    for(int i = 0;i<m;i++)
    {
        int a,b,c;
        cin>>a>>b>>c;
        edges[i] = {a,b,c};
    }
    bellman_ford();
    
    if(dist[n]>0x3f3f3f3f/2)puts("impossible");
    else cout<<dist[n]<<endl;
    
    return 0;
}

我就在这里补充我自己当时疑惑的一个点吧。

​ 对于memcpy(last,dist,sizeof dist);这一行,我们为什么在每次迭代刚开始时,需要备份一下当前状态的dist数组呢,我们要知道,每次迭代,我们用已经确定了dist数组的点(也就dist数组不再是0x3f3f3f3f)的点,同时去向外延伸一个单位的长度去更新其他的点。这里有两个很关键的词,同时一个单位,设想如果我们不去备份,我用A点去更新了距离一个单位的B点,我之后又可以用这个B点去更新距离B点一个单位的点,穷穷不尽,这样我在一次迭代之中,就更新了长度远远不止1的一条路径,就和我们写的这个for循环:

//不超过k条边我们就设定循环最大值为k
for(int i=0;i<k;i++)

就相互冲突了,我们的目的是想做到每次更新,都只更新长度为1的边。显然如果我们备份一下dist数组,我们每次的更新,就只会用在每一轮迭代开始时候已经确定dist的点去更新,且只更新一个长度,不会出现我在这一轮更新出来的新的点,在我们这一轮更新也会被用上去更新别的点,这就造成了一种我们不希望的串联,我们希望这一轮迭代更新出来的点,只是在下一轮更新的时候才开始投入使用。

本人讲得肯定不够浅显,不懂的童鞋们可以去看一下y总的视频讲解:

AcWing 853. 有边数限制的最短路 - AcWing 传送点在16:38处。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值