求助,48分,dijkstra 堆优化,c++, 超时

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

gogododone @ 2023-02-05 20:55:25

使用的是优先队列,但是 #2 #3 #6 case 超时了。。。

有大佬能帮忙分析下哪里耗时了嘛?

感谢感谢~~

代码如下:

    #include <iostream>
    #include <vector>
    #include <queue>
    using namespace std;

    #define MAXN 500001
    #define INF ((1<<31)-1)

    int VERTEX;
    int EDGE;
    struct Edge
    {
        int to, w, next;
    };

    Edge edges[MAXN];
    int head[MAXN], cnt;

    void addEdge(int from, int to, int w)
    {
        edges[++cnt].to = to;
        edges[cnt].w = w;
        edges[cnt].next = head[from];
        head[from] = cnt;
    }

    void dijkstra(int start, vector<int>& dist)
    {
        dist[start] = 0;

        vector<int> visited(VERTEX+1, 0);

        priority_queue<pair<int,int>,vector<pair<int,int>>,greater<pair<int,int>>> _q;
        _q.push({dist[start],start});

        while (!_q.empty())
        {
            int minDist = _q.top().first;
            int from = _q.top().second;
            _q.pop();

            visited[from] = 1;

            for (int e=head[from]; e; e=edges[e].next)
            {
                int to = edges[e].to;
                int w = edges[e].w;
                if (!visited[to] && dist[to] > dist[from] + w)
                {
                    dist[to] = dist[from] + w;
                    _q.push({dist[to], to});
                }
            }
        }
    }

    int main()
    {
        int start;
        scanf("%d%d%d", &VERTEX, &EDGE, &start);
        for (int i=1; i<=EDGE; i++)
        {
            int from, to, w;
            scanf("%d%d%d", &from, &to, &w);
            addEdge(from, to, w);
        }
        vector<int> dist(VERTEX+1, INF);
        dijkstra(start, dist);
        for (int i=1; i<=VERTEX; i++)
            printf("%d ", dist[i]);
        printf("\n");
        return 0;
    }

by Lysea @ 2023-02-05 21:11:52

@gogododone 将visited[from] = 1;前面加一句if(visited[from]) continue;if (!visited[to] && dist[to] > dist[from] + w)可以改成if (dist[to] > dist[from] + w)


by gogododone @ 2023-02-05 21:45:00

@Sands_Of_Time 非常感谢解答!!这种改法的确可以全部 AC。

但是我还是比较疑惑,这样写快的原因在哪里?

按照我的写法,我每次加入到队列中的顶点,都是没有被收录过的。

所以每次 from=_q.top().second; 时, if (visited[from]) 应该都是 false 才对呀。

希望有空的话再指教一下,感谢感谢!!


by gogododone @ 2023-02-06 20:40:10

我找到原因了,因为一个顶点可能会被多次加入队列中。 我们只需要处理第一次加入的那个节点,后续的可以直接跳过。

我把这个和 SPFA 中搞混了。


|