关于使用bool operator的堆与存pair的堆在此题中的不同

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

tx774 @ 2023-09-18 21:14:09

tr

第一份代码使用了bool operator但是WA #1 & #5

而第二份代码成功AC

第一份:

/*
2018年7月19日,某位同学在 NOI D1T1归程一题里非常熟练地使用了一个广为人知的算法求最短路。
然后呢?
100 →60;
Ag →Cu
最终,他因此没能与理想的大学达成契约。
大K 衷心祝愿大家不再重蹈覆辙。
*/
#include<bits/stdc++.h>
using namespace std;
#define int long long
const int N=1e6+5;
const int INF=0x3f3f3f3f3f3f3f3f;

int n,m,s,dis[N];//dis数组表示起点到某点的最短路大小
bool vis[N];

struct Edge{
    int to,w,nxt;
}e[N*2];int tot,head[N];

inline void addedge(int u,int v,int w)//链式前向星存图。 
{e[++tot].to=v;e[tot].w=w;e[tot].nxt=head[u];head[u]=tot;}

struct cmp{
    bool operator()(const int &x, const int &y) const{
        return dis[x]>dis[y];
    }//Priaority_queue 的 Compare 需要使用结构体的运算符重载完成,直接 bool cmp 是无法通过编译的。
};priority_queue<int,vector<int>,cmp> q;
void dijkstra(int o)
{
    memset(dis,0x3f,sizeof(dis));//初始化
    memset(vis,0,sizeof(vis));
    dis[o] = 0;
    q.push(o);
    while(!q.empty())
    {        
        int now=q.top();q.pop();
        if(vis[now]) continue;
        vis[now]=1;
        for(int i=head[now];i;i=e[i].nxt)
        {
            int to=e[i].to;
            if(dis[to]>dis[now]+e[i].w)
            {
                dis[to]=dis[now]+e[i].w;
                q.push(to);
            }
        }            
    }
}

signed main()
{
    cin>>n>>m>>s;
    for(int i=1,u,v,w;i<=m;++i)
    {
        cin>>u>>v>>w;addedge(u,v,w);
    }
    dijkstra(s);
    for(int i=1;i<=n;++i)
    {
        cout<<dis[i]<<" ";      
    }
    return 0;
}

第二份:

/*
2018年7月19日,某位同学在 NOI D1T1归程一题里非常熟练地使用了一个广为人知的算法求最短路。
然后呢?
100 →60;
Ag →Cu
最终,他因此没能与理想的大学达成契约。
大K 衷心祝愿大家不再重蹈覆辙。
*/
#include<bits/stdc++.h>
using namespace std;
#define int long long
const int N=1e6+5;
const int INF=0x3f3f3f3f3f3f3f3f;

int n,m,s,dis[N];//dis数组表示起点到某点的最短路大小
bool vis[N];

struct Edge{
    int to,w,nxt;
}e[N*2];int tot,head[N];

inline void addedge(int u,int v,int w)//链式前向星存图。 
{e[++tot].to=v;e[tot].w=w;e[tot].nxt=head[u];head[u]=tot;}

struct cmp{
    bool operator()(const int &x, const int &y) const{
        return dis[x]<dis[y];
    }//Priaority_queue 的 Compare 需要使用结构体的运算符重载完成,直接 bool cmp 是无法通过编译的。
};//priority_queue<int,vector<int>,cmp> q;
void dijkstra(int o)
{
    memset(dis,0x3f,sizeof(dis));//初始化
    memset(vis,0,sizeof(vis));
    priority_queue<pair<int,int> > q;
    dis[o] = 0;
    q.push({-dis[o], o});
    while(!q.empty())
    {        
        int now=q.top().second;q.pop();
        if(vis[now]) continue;
        vis[now]=1;
        for(int i=head[now];i;i=e[i].nxt)
        {
            int to=e[i].to;
            if(dis[to]>dis[now]+e[i].w)
            {
                dis[to]=dis[now]+e[i].w;
                q.push({-dis[to], to});
            }
        }            
    }
}

signed main()
{
    cin>>n>>m>>s;
    for(int i=1,u,v,w;i<=m;++i)
    {
        cin>>u>>v>>w;addedge(u,v,w);
    }
    dijkstra(s);
    for(int i=1;i<=n;++i)
    {
        cout<<dis[i]<<" ";      
    }
    return 0;
}

by yukimianyan @ 2023-09-18 21:41:44

第一种写法会破坏堆性质,后面发生什么就不为人知了


by tx774 @ 2023-09-18 22:07:37

@yukimianyan Why?


by Code_星云 @ 2023-09-20 13:38:05

因为你这样写在实时比较时用了新的 dis 数组,但是你应该用之前求时的 dis,不然贪心是错的


by tx774 @ 2023-09-25 21:21:45

@Code_星云 但是难道不是每次更新dis时都会加一个node进堆吗,这样对于每个node比较时不都是最新dis的吗?

有没有样例或者图啥的啊

阿里嘎多:)


by d95a_4c1d @ 2023-11-09 17:01:32

@tx774 可能dis改变之后那个堆就不是一个合法的堆了(不满足父亲比儿子小), 堆的各种操作也会出错


by d95a_4c1d @ 2023-11-09 17:02:11

@tx774 此时这个堆是没法每次取最小的


|