BZOJ4198或UOJ130 荷马史诗 【K叉哈夫曼树】【堆】

题目链接:
http://www.lydsy.com/JudgeOnline/problem.php?id=4198
http://uoj.ac/problem/130

题解:
用一个堆来维护一个K叉哈夫曼树,如果无法合并(即n-1不为k-1的倍数时),就补充n-k个虚拟节点,节点的权值为0(不会影响结果),再合并即可。

代码:

#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
#include <queue>

using namespace std;

typedef long long LL;

const int inf = 1 << 26;

struct trees {
    LL v, h;
};

bool operator<(trees a, trees b){
    if(a.v != b.v) return a.v > b.v;
    return a.h > b.h;   
}

priority_queue<trees> q;
int n, k;

int main(){
    scanf("%d %d", &n, &k);
    for ( int i = 1; i <= n; i ++ ) {
        trees a;
        scanf("%lld", &a.v);
        a.h = 1;
        q.push(a);
    }

    LL top = 0;
    if((n-1)%(k-1) != 0) top += k-1-(n-1)%(k-1);    // 需要补为 0 的结点的个数

    for ( int i = 1; i <= top; i ++ ) {
        trees need;
        need.v = 0; need.h = 1;
        q.push(need);
    } 

    top += n;
    LL ans = 0;
    while(top != 1) {
        trees a;
        LL temp = 0, mx = 0;
        for ( int i = 1; i <= k; i ++ ) {
            a = q.top(); temp += a.v;
            mx = max(mx, a.h); q.pop();
        }

        ans += temp;
        a.v = temp; a.h = mx+1;
        q.push(a);
        top -= k-1;
    }
    printf("%lld\n%lld\n", ans, q.top().h-1);

    return 0;
}

猜你喜欢

转载自blog.csdn.net/qq_34896694/article/details/69803708