论 Fibonacci 堆的常数到底有多少

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

cancan123456 @ 2022-10-15 09:42:09

均使用 scanf&printf 进行 I/O。

STL 中的 priority_queue,复杂度 O((n+m)\log m) 用了 778ms。

手写的 Fibonacci 堆用了,复杂度 O(n\log n+m) 874ms。


by cancan123456 @ 2022-10-15 09:42:28

代码:

#include <cstdio>
#include <vector>
using namespace std;
const int N = 100000;
void print_heap(int n);
struct KeyValue {
    int u, dis;
    KeyValue() {
    }
    KeyValue(int u_, int dis_) {
        u = u_;
        dis = dis_;
    }
};
bool operator < (const KeyValue & a, const KeyValue & b) {
    return a.dis < b.dis;
}
struct FibonacciHeapNode {
    KeyValue key;
    FibonacciHeapNode * child, * left, * right, * father;
    int degree;
    bool mark;
    FibonacciHeapNode(KeyValue x) {
        key = x;
        child = left = right = father = nullptr;
        degree = 0;
        mark = false;
    }
    void insert(FibonacciHeapNode * p) {
        p -> left = left;
        p -> right = this;
        left -> right = p;
        left = p;
    }
    void remove() {
        right -> left = left;
        left -> right = right;
        left = right = this;
    }
    void cut() {
        father -> degree--;
        if (left == this) {
            father -> child = nullptr;
        } else {
            if (father -> child == this) {
                father -> child = left;
            }
            remove();
        }
        father = nullptr;
    }
};
int log2(int x) {
    for (int i = 0; ; i++) {
        if (x < (1 << i)) {
            return i - 1;
        }
    }
}
void swap(FibonacciHeapNode * & a, FibonacciHeapNode * & b) {
    FibonacciHeapNode * temp = a;
    a = b;
    b = temp;
}
struct FibonacciHeap {
    FibonacciHeapNode * min, ** cons;
    int node_number;
    FibonacciHeap() {
        min = nullptr;
    }
    FibonacciHeapNode * insert(KeyValue key) {
        FibonacciHeapNode * p = new FibonacciHeapNode(key);
        if (min == nullptr) {
            min = p;
            min -> left = min -> right = min;
        } else {
            min -> insert(p);
            if (p -> key < min -> key) {
                min = p;
            }
        }
        node_number++;
        return p;
    }
    void merge(FibonacciHeap * other) {
        min -> left -> right = other -> min;
        other -> min -> left -> right = min;
        swap(min -> left, other -> min -> left);
        if (other -> min -> key < min -> key) {
            min = other -> min;
        }
        other -> min = nullptr;
        node_number += other -> node_number;
    }
    KeyValue find_min() {
        return min -> key;
    }
    void consolidate() {
        int length = log2(node_number) + 2;
        cons = new FibonacciHeapNode * [length];
        for (int i = 0; i < length; i++) {
            cons[i] = nullptr;
        }
        while (min != nullptr) {
            FibonacciHeapNode * p = min;
            if (min -> left != min) {
                min = min -> right;
                p -> remove();
            } else {
                min = nullptr;
            }
            if (cons[p -> degree] == nullptr) {
                cons[p -> degree] = p;
            } else {
                if (p -> key < cons[p -> degree] -> key) {
                    swap(cons[p -> degree], p);
                }
                if (cons[p -> degree] -> child == nullptr) {
                    cons[p -> degree] -> child = p;
                } else {
                    cons[p -> degree] -> child -> insert(p);
                }
                cons[p -> degree] -> degree++;
                p -> father = cons[p -> degree];
                int now = p -> degree;
                while (cons[now + 1] != nullptr) {
                    if (cons[now] -> key < cons[now + 1] -> key) {
                        swap(cons[now], cons[now + 1]);
                    }
                    cons[now + 1] -> child -> insert(cons[now]);
                    cons[now + 1] -> degree++;
                    cons[now] -> father = cons[now + 1];
                    cons[now] = nullptr;
                    now++;
                }
                cons[now + 1] = cons[now];
                cons[now] = nullptr;
            }
        }
        int count = 0;
        for (int i = 0; i < length; i++) {
            if (cons[i] != nullptr) {
                cons[count] = cons[i];
                count++;
            }
        }
        for (int i = 0; i < count; i++) {
            cons[i] -> left = cons[(i - 1 + count) % count];
            cons[i] -> right = cons[(i + 1) % count];
        }
        min = cons[0];
        for (int i = 1; i < count; i++) {
            if (cons[i] -> key < min -> key) {
                min = cons[i];
            }
        }
        delete [] cons;
    }
    void extract_min() {
        if (min -> child != nullptr) {
            while (min -> child != nullptr) {
                FibonacciHeapNode * p = min -> child;
                p -> cut();
                min -> insert(p);
            }
        }
        if (node_number == 1) {
            min = nullptr;
        } else {
            FibonacciHeapNode * p = min -> right;
            min -> remove();
            delete min;
            min = p;
        }
        node_number--;
        if (node_number >= 1) {
            consolidate();
        }
    }
    void cascading_cut(FibonacciHeapNode * p) {
        if (p -> father != nullptr) {
            if (p -> mark) {
                cascading_cut(p -> father);
                p -> cut();
                min -> insert(p);
                p -> father = nullptr;
                p -> mark = false;
            } else {
                p -> mark = true;
            }
        }
    }
    void decrease_key(FibonacciHeapNode * p, KeyValue new_key) {
        if (p -> key < new_key) {
            printf("Error The new key is greater than current key.\n");
            return;
        }
        p -> key = new_key;
        if (p -> father != nullptr && new_key < p -> father -> key) {
            cascading_cut(p -> father);
            p -> cut();
            min -> insert(p);
            p -> mark = false;
        }
        if (p -> key < min -> key) {
            min = p;
        }
    }
    void delete_node(FibonacciHeapNode * p) {
        decrease_key(p, KeyValue(p -> key.u, -2147483647 - 1));
        extract_min();
    }
};
struct Edge {
    int v, w;
    Edge() {
    }
    Edge(int v_, int w_) {
        v = v_;
        w = w_;
    }
};
vector < Edge > edge[N];
int dis[N];
FibonacciHeapNode * node[N];
FibonacciHeap heap;
int main() {
    int n, m;
    scanf("%d %d %*d", &n, &m);
    for (int u, v, w, i = 1; i <= m; i++) {
        scanf("%d %d %d", &u, &v, &w);
        u--;
        v--;
        edge[u].push_back(Edge(v, w));
    }
    for (int u = 0; u < n; u++) {
        dis[u] = 0x3f3f3f3f;
    }
    dis[0] = 0;
    for (int i = 0; i < n; i++) {
        node[i] = heap.insert(KeyValue(i, dis[i]));
    }
    for (int u, i = 0; i < n; i++) {
        u = heap.find_min().u;
        node[u] = nullptr;
        heap.extract_min();
        for (Edge to : edge[u]) {
            if (dis[to.v] > dis[u] + to.w) {
                dis[to.v] = dis[u] + to.w;
                heap.decrease_key(node[to.v], KeyValue(to.v, dis[to.v]));
            }
        }
    }
    for (int i = 0; i < n; i++) {
        printf("%d ", dis[i]);
    }
    return 0;
}

by wangzikang @ 2022-10-15 09:50:51

zgc 爆切Fib堆%%%%%%

建议学习一下这个


by sunrise1024 @ 2022-10-15 09:55:06

@cancan123456 这里n和m差距不大,常数大点就慢了,要试这个代码的效率的话建议跑完全图


by 鏡音リン @ 2022-10-15 10:12:02

@sunrise1024 完全图谁拿堆跑dijkstra啊?


by cancan123456 @ 2022-10-15 10:44:03

@sunrise1024 完全图直接暴力都比堆快。


by cancan123456 @ 2022-10-15 10:44:45

要不造个 1e6 级别的图跑跑?


by cancan123456 @ 2022-10-15 10:49:16


by cancan123456 @ 2022-10-15 11:28:20

n=10^6,m=2\times10^6$,Fibonacci 堆 $8.642\texttt s$,优先队列 $7.5\texttt s

by bai_tang @ 2022-10-15 11:57:38


|