https://ac.nowcoder.com/acm/contest/65157/F
贴出一个比较高效,且简洁的代码
贪心策略:
1、优先合并两个权值最小的数。
2、当有多个权值最小的数,优先合并两个层数最小的数。
解题思路:
因为哈夫曼树在合并的过程中,产生的数X按照<权值,层数>从小到大,
但已经给出1-n的数,所以当X<=n时,不能直接插在队列后面,要使用优先队列。
而当X>n时,X可以直接插在队列后面,可以使用双端队列,使用双端队列是为了方便后续操作。
#include<bits/stdc++.h>
using namespace std;
#define int long long 
#define x first
#define y second
#define PII pair<int,int>//层数,等价类数量
#define PIII pair<pair<int,int>,int>//价值,层数,等价类数量
priority_queue<PIII,vector<PIII>,greater<PIII>>q;
deque<PII>dq;

int n,deep,sum;
signed main(){
    ios::sync_with_stdio(0),cin.tie(0),cout.tie(0);
    cin >> n ;
    for(int i=1;i<=n;i++){
        int p;cin >> p;sum+=p;
        if(p)q.push({{i,0},p});
    }

    while(!q.empty()){
        auto a=q.top();q.pop();

        if(q.empty()&&a.y==1&&dq.empty()){
            cout << a.x.y << '\n';
            return 0;
        }
     
        if(a.y/2){
            if(a.x.x*2<=n)q.push({{a.x.x*2,a.x.y+1},a.y/2});
            else dq.push_back({a.x.y+1,a.y/2});
        }
           
        if(a.y%2){
            if(!q.empty()){
                auto b=q.top();q.pop();
                if(b.y-1>0)q.push({{b.x.x,b.x.y},b.y-1});
                if(b.x.x+a.x.x<=n)q.push({{b.x.x+a.x.x,max(a.x.y,b.x.y)+1},1});
                else dq.push_back({max(a.x.y,b.x.y)+1,1});
            }
            else{
                auto da=dq.front();dq.pop_front();
                if(da.y-1)dq.push_front({da.x,da.y-1});
                dq.push_back({max(da.x,a.x.y)+1,1});
            }
        }       
    }
    while(!dq.empty()){
        auto a=dq.front();dq.pop_front();
        if(dq.empty()&&a.second==1){
            cout << a.first << '\n' ;return 0;
        }
        if(a.second/2){
            dq.push_back({a.first+1,a.second/2});}
        if(a.second%2){
            auto b=dq.front();dq.pop_front();
            if(b.second-1>0)dq.push_front({b.x,b.y-1});
            dq.push_back({max(b.x,a.x)+1,1});
        }
    }
    return 0;
}