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

京公网安备 11010502036488号