哈夫曼树的构建基于贪心思想,每次取出最小的两个结点合成一个节点并重复直到只剩下一个节点即根节点。
哈夫曼编码即在此基础上从根节点到某个叶子节点的路径,如果是左儿子就为0,右儿子为1,本题要求左儿子小于等于右儿子,所以构建是特判即可,最后倒退父节点找到答案。
#include <iostream>
#include <algorithm>
#include <cstring>
#include <vector>
#include <queue>
using namespace std;
typedef pair<int,int> PII;
const int N = 1e5+10;
int p[N],l[N],r[N],w[N],idx;
void add(int x,int lc,int rc)
{
w[idx]=x;
l[idx]=lc;
r[idx]=rc;
p[lc]=p[rc]=idx;
idx++;
}
void add(int x)
{
w[idx++]=x;
}
void solve()
{
memset(p,-1,sizeof p);
int n;
cin>>n;
priority_queue<PII,vector<PII>,greater<PII> >q;
for(int i=0;i<n;i++)
{
int x;
cin>>x;
add(x);
q.push({x,i});
}
while(q.size()>1)
{
PII a=q.top();q.pop();
PII b=q.top();q.pop();
int x=a.first+b.first;
if(a.first<=b.first)
{
add(x,a.second,b.second);
}
else add(x,b.second,a.second);
q.push({x,idx-1});
}
for(int i=0;i<n;i++)
{
string res;
int cur=i;
while(1)
{
if(p[cur]==-1)break;
if(l[p[cur]]==cur)
{
res='0'+res;
}
else res='1'+res;
cur=p[cur];
}
cout<<res<<"\n";
}
}
signed main()
{
solve();
return 0;
}