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; }