dijkstra 邻接表 链式前向星性能差距大且TLE

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

hanxinyao @ 2024-12-14 17:57:22

dijkstra

邻接表做法:开O2 84pts 不开O2 48pts

#include <bits/stdc++.h>
#define int long long

using namespace std;

struct edge {
    int v,w;

};
struct pt {
    int length,num;
    friend bool operator<(pt a,pt b) {
        return a.length > b.length;
    }
};

vector<edge> mp[100100];
int vis[100100],dist[100100];
int n,m,s;
int u,v,w;
void dijkstra(int st) {
    priority_queue<pt> q;
    q.push({0,st});
    for (int i = 1; i <= n; i++) {
        dist[i] = INT_MAX;

    }
    dist[st] = 0;
    while(q.size() != 0) {
        pt now = q.top();
        q.pop();
        vis[now.num] = 1;
        for (auto t:mp[now.num]) {
            if (vis[t.v] == 1) continue;
            //printf(" dist[%lld]= %lld t.w = %lld dist[t.v] = %lld\n",now.num,dist[now.num],t.w ,dist[t.v]); 
            if (dist[now.num] + t.w < dist[t.v]) {
                dist[t.v] = dist[now.num] + t.w;
                //printf("update dist[%lld] = dist[%lld]:%lld + %lld\n",t.v,now.num,dist[now.num],t.w); 
                q.push({dist[t.v],t.v});
            }
                //printf("now = [%lld,%lld] t = [%lld,%lld] dist[%lld]= %lld\n",now.length,now.num,t.v,t.w,t.v,dist[t.v]);
        }
    }
}
signed main() {
    cin >> n >> m >> s;
    for (int i = 1; i <= m; i++) {
        cin >> u >> v >> w;
        mp[u] .push_back({v,w});
    }

    dijkstra(s);
    for (int i= 1;i<= n;i++)
    {
        cout << dist[i]<< " ";
    }
}

链式前向星 都是48pts

#include <bits/stdc++.h>
#define int long long
using namespace std;

struct edge
{
    int v,w,next;
}e[200010];
struct pt
{
    int num,d;
    friend bool operator<(pt a,pt b)
    {
        return a.d > b.d;
    }
};
int cnt,head[100010],vis[100010],dist[100010];
int u,v,w;
int n,m,s;

void add(int u,int v,int w)
{
    e[++cnt].v = v;
    e[cnt].w = w;
    e[cnt].next = head[u];
    head[u] = cnt;
}

void dijkstra(int st)
{
    for (int i = 1;i <= n;i++)
    {
        dist[i] = LLONG_MAX;
    }
    dist[st] = 0;
    priority_queue<pt > q;
    q.push({st,dist[st]});
    while (q.size())
    {
        pt now = q.top();
        q.pop();
        vis[now.num] = 1;
        //printf("now = %lld",now);
        for (int i = head[now.num];i;i = e[i].next)
        {
            if (vis[e[i].v] == 0)
            {
                if (dist[now.num] + e[i].w < dist[e[i].v])
                {
                    dist[e[i].v] = dist[now.num] + e[i].w;
                    q.push({e[i].v,dist[e[i].v]});

                    //printf("\tnow = %lld v = %lld (now,v) = %lld dist[now] = %lld dist[v] = %lld\n",now,e[i].v,e[i].w,dist[now],dist[e[i].v]);
                }
            }
        }
    }

}
signed main()
{
//  freopen("P4779_3.in","r",stdin);
//  freopen("P4779.out","w",stdout);
    cin >> n >> m >> s;
    for (int i = 1;i <= m;i++)
    {
        cin >> u >> v >> w;
        add(u,v,w);
    }
    dijkstra(s);

    for (int i = 1;i <= n;i++)
    {
        cout << dist[i] << " ";
    }
}

希望有dalao看看


by pika_ @ 2024-12-14 18:00:59

TLE?


by pika_ @ 2024-12-14 18:02:01

为什么我Dijkstra+邻接表能AC


by Poole_tea @ 2024-12-14 18:17:32

不要开longlong,数据范围到不了longlong,开longlong会变慢的


by hanxinyao @ 2024-12-14 18:59:02

@Poole_tea 把longlong改int只能快不到10ms https://www.luogu.com.cn/record/194097919 https://www.luogu.com.cn/record/194480155


by Poole_tea @ 2024-12-14 19:06:18

我给你改成这样就过了

#include <bits/stdc++.h>

using namespace std;

struct edge {
    int v,w;

};
struct pt {
    int length,num;
    friend bool operator<(pt a,pt b) {
        return a.length > b.length;
    }
};

vector<edge> mp[100100];
int vis[100100],dist[100100];
int n,m,s;
int u,v,w;
void dijkstra(int st) {
    priority_queue<pt> q;
    q.push({0,st});
    for (int i = 1; i <= n; i++) {
        dist[i] = INT_MAX;

    }
    dist[st] = 0;
    while(q.size() != 0) {
        pt now = q.top();
        q.pop();
        vis[now.num] = 1;
        for (auto t:mp[now.num]) {
            if (vis[t.v] == 1) continue;
            //printf(" dist[%lld]= %lld t.w = %lld dist[t.v] = %lld\n",now.num,dist[now.num],t.w ,dist[t.v]); 
            if (dist[now.num] + t.w < dist[t.v]) {
                dist[t.v] = dist[now.num] + t.w;
                //printf("update dist[%lld] = dist[%lld]:%lld + %lld\n",t.v,now.num,dist[now.num],t.w); 
                q.push({dist[t.v],t.v});
            }
                //printf("now = [%lld,%lld] t = [%lld,%lld] dist[%lld]= %lld\n",now.length,now.num,t.v,t.w,t.v,dist[t.v]);
        }
    }
}
int main() {
    cin >> n >> m >> s;
    for (int i = 1; i <= m; i++) {
        cin >> u >> v >> w;
        mp[u] .push_back({v,w});
    }

    dijkstra(s);
    for (int i= 1;i<= n;i++)
    {
        cout << dist[i]<< " ";
    }
}

by Poole_tea @ 2024-12-14 19:14:33

还有就是判vis应该这样写

while (q.size())
    {
        pt now = q.top();
        q.pop();
        if (vis[now.num]) continue ;
        vis[now.num] = 1;
        //printf("now = %lld",now);
        for (int i = head[now.num];i;i = e[i].next)
        {
            if (dist[now.num] + e[i].w < dist[e[i].v])
            {
                dist[e[i].v] = dist[now.num] + e[i].w;
                q.push({e[i].v,dist[e[i].v]});

                    //printf("\tnow = %lld v = %lld (now,v) = %lld dist[now] = %lld dist[v] = %lld\n",now,e[i].v,e[i].w,dist[now],dist[e[i].v]);
            }
        }
    }

你那样写的实质其实就是spfa了,所以会慢


by Poole_tea @ 2024-12-14 19:57:01

@hanxinyao


by hanxinyao @ 2024-12-14 20:16:04

@Poole_tea 过了,谢谢

还有想问一下判断vis的两种方法有什么区别吗


by Poole_tea @ 2024-12-14 21:46:41

@hanxinyaodij的vis是判断是否松弛过,而spfa的是判断是否在队列中,你那种写法是spfa的写法,所以会慢


|