简体   繁体   English

Dijkstra的算法问题

[英]Dijkstra's algorithm question

In the code below: 在下面的代码中:

#define MAX_VERTICES 260000

#include <fstream>
#include <vector>
#include <queue>
#define endl '\n'
using namespace std;

struct edge {
    int dest;
    int length;
};

bool operator< (edge e1, edge e2) {
    return e1.length > e2.length;
}

int C, P, P0, P1, P2;
vector<edge> edges[MAX_VERTICES];
int best1[MAX_VERTICES];
int best2[MAX_VERTICES];

void dijkstra (int start, int* best) {
    for (int i = 0; i < P; i++) best[i] = -1;
    best[start] = 0;
    priority_queue<edge> pq;
    edge first = { start, 0 };
    pq.push(first);
    while (!pq.empty()) {
        edge next = pq.top();
        pq.pop();
        if (next.length != best[next.dest]) continue;
        for (vector<edge>::iterator i = edges[next.dest].begin(); i != edges[next.dest].end(); i++) {
            if (best[i->dest] == -1 || next.length + i->length < best[i->dest]) {
                best[i->dest] = next.length + i->length;
                edge e = { i->dest, next.length+i->length };
                pq.push(e);
            }
        }
    }
}

int main () {
    ifstream inp("apple.in");
    ofstream outp("apple.out");

    inp >> C >> P >> P0 >> P1 >> P2;
    P0--, P1--, P2--;
    for (int i = 0; i < C; i++) {
        int a, b;
        int l;
        inp >> a >> b >> l;
        a--, b--;
        edge e = { b, l };
        edges[a].push_back(e);
        e.dest = a;
        edges[b].push_back(e);
    }

    dijkstra (P1, best1);           // find shortest distances from P1 to other nodes
    dijkstra (P2, best2);           // find shortest distances from P2 to other nodes

    int ans = best1[P0]+best1[P2];  // path: PB->...->PA1->...->PA2
    if (best2[P0]+best2[P1] < ans) 
        ans = best2[P0]+best2[P1];  // path: PB->...->PA2->...->PA1
    outp << ans << endl;
    return 0;
}

What is this: if (next.length != best[next.dest]) continue; 这是什么: if (next.length != best[next.dest]) continue; used for? 用于? Is it to avoid us situations where going through the loop will give us the same answer that we already have? 这是为了避免我们遇到循环的情况会给我们相同的答案吗?

Thanks! 谢谢!

I guess you are contemplating the case where your priority_queue contains 2 times the same edge, but each one with a different "length". 我想你正在考虑你的priority_queue包含2倍相同边缘的情况,但每个都有不同的“长度”。

This could happen if you push edge X which has a length of Y, and afterwards push edge X again, but this time it has a length < Y. That is why, if the length of that edge, isn't the lowest you've found for that edge so far, you ommit it in that loop's iteration. 如果你推动长度为Y的边缘X,然后再次推动边缘X,这可能会发生,但这次它的长度<Y.这就是为什么,如果边缘的长度不是最低的那么你呢?到目前为止已找到该边缘,你在该循环的迭代中省略它。

That line is a way to handle the fact that c++'s priority_queue does not have a decrease_key function. 该行是一种处理c ++的priority_queue没有reduce_key函数这一事实的方法。

That is, when you do pq.push(e) and there is already an edge with the same destination in the heap you would prefer to decrease the key of the edge already in the heap. 也就是说,当你执行pq.push(e)并且堆中已存在具有相同目标的边时,您希望减少堆中已存在的边的键。 This is not easily done with c++'s priority_queue and so a simple way to handle it is to allow multiple edges in the heap corresponding to the same destination and ignoring all but the first (for each dest) that you pop from the heap. 使用c ++的priority_queue并不容易做到这一点,因此处理它的一种简单方法是允许堆中的多个边对应于同一目标,并忽略从堆中弹出的第一个(对于每个dest)。

Note that this changes the complexity from O(ElogV) to O(ElogE) . 请注意,这会将复杂性从O(ElogV)更改为O(ElogE)

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM