PS:未来计算和未来算算均为四川省成都市树德中学信竞团队oier专用网站,如果读过题了可以跳过题目描述直接到题解部分
提交链接1:未来计算 3219 Huffman编码树
提交链接2:未来算算 1260 Huffman编码树
题目
题目描述
构造一个具有 n 个外部节点的扩充二叉树,每个外部节点 k[i] 有一个w[i] 对应,作为该外部节点的权。使得这个扩充二叉树的叶节点带权外部路径长度总和最小:
min(w[1]*l[1]+w[2]*l[2]+w[3]*l[3]+…+w[n]*l[n])
w[i] :每个节点的权值。
l[i] :根节点到第 i 个外部叶子节点的距离。
编程计算最小外部路径长度总和。
输入格式
第一行输入一个整数 n ,外部节点的个数。第二行输入 n 个整数,代表各个外部节点的权值。
2≤n≤100
2≤n≤100
输出格式
输出最小外部路径长度总和。
样例
样例输入
4
1 1 3 5
样例输出
17
题解
哈夫曼编码树
这道题的算法显然是哈夫曼编码树,因为本人懒得画图,因此推荐这篇文章,个人认为讲解的是非常清楚的(反正我当时其实是看这个看懂的)。
图解哈夫曼(Huffman)编码树_JavaEdge.的博客-CSDN博客
代码实现
我也不知道我这么写是不是正解,反正是过了的。
//未来计算 3219 未来算算 1260 Huffman编码树
#include<iostream>
#include<cstdio>
using namespace std;
int n;
int a[110];
int cnt;
int t;
int x1;
int x2;
long long ans;
struct node{
int w;
int h;
int lc;
int rc;
}w[440];
void insert(int x){
int p=++cnt;
a[p]=x;
while(p!=1&&w[a[p/2]].w>w[a[p]].w){
swap(a[p/2],a[p]);
p/=2;
}
}
void pop(){
swap(a[cnt],a[1]);
--cnt;
int p=1;
int k=1;
while(1){
if((p<<1)<=cnt&&w[a[k]].w>w[a[(p<<1)]].w){
k=(p<<1);
}
if(((p<<1)|1)<=cnt&&w[a[k]].w>w[a[((p<<1)|1)]].w){
k=(p<<1|1);
}
if(k==p){
break;
}
swap(a[k],a[p]);
p=k;
}
}
void build(int x,int y){
++t;
w[t].w=w[x].w+w[y].w;
w[t].lc=x;
w[t].rc=y;
}
void dfs(int x,int h){
w[x].h=h;
if(w[x].lc){
dfs(w[x].lc,h+1);
}
if(w[x].rc){
dfs(w[x].rc,h+1);
}
}
int main(){
scanf("%d",&n);
for(int i=1;i<=n;++i){
scanf("%d",&w[i].w);
insert(i);
}
t=cnt;
while(cnt!=1){
x1=a[1];
pop();
x2=a[1];
pop();
build(x1,x2);
insert(t);
}
dfs(t,0);
for(int i=1;i<=n;++i){
ans+=w[i].w*w[i].h;
}
printf("%lld\n",ans);
return 0;
}