关于dij堆中为何需要存(u,d)二元组而不可以只存结点编号u

P4779 【模板】单源最短路径(标准版)

Albert_van @ 2022-07-14 19:52:13

RT,当时学得有些囫囵吞枣,刚碰到一道最短路题突然不懂了

我的理解,每次松弛时我们都会更新外面的 dis 数组,任何时候 u 可以通过 dis 唯一对应到 当前 s\to u 最短路径的长度,堆内部直接以 dis 的大小为基准排序即可,每次从堆里取出元素 x 时能够保证 dis_x=\delta(s,x) 的长度。

如下代码可以通过弱化版,本题则 WA68:

#include <cstdio>
#include <vector>
#include <queue>
#include <cstring>

using namespace std;

const int N=1e5+1.14514,inf=0x3f3f3f3f;

struct edg{int v,w;};

vector<edg> vc[N];

int f[N],s;bool vis[N];

struct cmp{bool operator()(int x,int y){return f[x]>f[y];}};

priority_queue<int,vector<int>,cmp> q;

void di_kstra(){
    memset(f,inf,sizeof(f));
    f[s]=0;q.push(s);
    while(!q.empty()){
        int now=q.top();q.pop();
        if(vis[now]) continue;vis[now]=1;
        for(auto [v,w]:vc[now]) if(f[v]>f[now]+w) f[v]=f[now]+w,q.push(v);
    }
}

int main()
{
    int n,m,u,v,w;scanf("%d%d%d",&n,&m,&s);
    for(int i=1;i<=m;++i) scanf("%d%d%d",&u,&v,&w),vc[u].push_back((edg){v,w});
    di_kstra();for(int i=1;i<=n;++i) printf("%d ",f[i]==inf?2147483647:f[i]);
}

求 dalao 解释下为什么我的想法是错的或者告诉我我写挂了,不胜感激。


by 小木虫 @ 2022-07-14 20:11:11

@Register_int 好好说话,没必要,人家好好问的问题


by Albert_van @ 2022-07-14 20:14:17

@小木虫 懂了蟹蟹。话说题解都不讲这个的吗,我当时看的博客也都没讲过


by 小木虫 @ 2022-07-14 20:14:48

@Albert_van 其实会手写堆就懂了


by rxjdasiwzl @ 2022-07-14 20:34:14

@小木虫 @register_int 为啥堆不能修改元素啊


by Register_int @ 2022-07-14 20:38:08

@rxjdasiwzl 堆的整体思想就是通过维护一个上小下大(上大下小)的结构来维护最小值。如果修改元素,就会破坏这种单调性,从而使整个堆结构遭到破坏,你的最短路也就寄了


by rxjdasiwzl @ 2022-07-14 22:32:07

@Register_int 谔谔,你修改之后和父亲比一下,比父亲小就和父亲交换一下,不就保持性质了吗


by Register_int @ 2022-07-15 07:39:46

@rxjdasiwzl 手写堆中确实可以这么做


by 小木虫 @ 2022-07-15 11:26:39

@rxjdasiwzl 你这复杂度假了xd


by 小木虫 @ 2022-07-15 11:26:59

@rxjdasiwzl 你试一下,应该在强数据下会TLE,复杂度不对


by rxjdasiwzl @ 2022-07-15 11:49:10

@小木虫 二叉堆树高 O(\log n),总共 O(m) 次修改,修改的复杂度 O(m\log n)


上一页 | 下一页