习题:荷马史诗(哈夫曼树&贪心)

题目

传送门

思路

笔者一开始是向trie树和贪心方面想,

但是经过机房巨佬的点拨,自己实际上就是写的哈夫曼树

关于哈夫曼树

我们实际上可以这样想,每一个单词就是一个点,点权就是它出现的次数

有一个很容易想到的贪心,点权越大的,他所拥有的长度就应该越小

我们就往这个方向去想,我们不需要知道每一个点具体编号

我们需要的只是它所出现的次数以及编号的长度

因为我们需要将最长的s的达到最短

我们其实可以将编号的过程抽象成一个个树的合并

这个树一定是k叉的

并且每一层只能有一个能往下拓展

所以我们用一个优先队列来维护每一个点的权值的大小顺序

之后取出前k个,合并之后,再塞进树里面就行了

整个过程中我们不需要建树,我们只是抽象成为一个过程而已

代码

#include<iostream>
#include<queue>
using namespace std;
struct node
{
    int dep;
    long long w;
    friend bool operator < (const node &a,const node &b)
    {
        if(a.w==b.w)
            return a.dep>b.dep;
        return a.w>b.w;
    }
}a[100005];
int n,k;
long long ans;
node cnt[15];
priority_queue<node> q;
int main()
{
    ios::sync_with_stdio(false);
    cin>>n>>k;
    for(int i=1;i<=n;i++)
    {
        long long w;
        cin>>w;
        q.push((node){0,w});
    }
    while((n-1)%(k-1))
    {
        n++; 
        q.push((node){0,1ll*0});
    }
    while(q.size()!=1)
    {
        for(int i=1;i<=k;i++)
        {
            cnt[i]=q.top();
            q.pop();
        }
        node t;
        t.dep=0;
        t.w=0;
        for(int i=1;i<=k;i++)
        {
            t.w+=cnt[i].w;
            t.dep=max(t.dep,cnt[i].dep);
        }
        t.dep++;
        q.push(t);
        ans+=t.w;
    }
    cout<<ans<<' '<<q.top().dep;
    return 0;
}

猜你喜欢

转载自www.cnblogs.com/loney-s/p/12076863.html
今日推荐