题目:
xiaok大佬最近再雇佣工人给他掰木棒。把一根长为L的木棒锯成两段,他需要支付给工人L元钱。xiaok大佬一开始只有长为L的一根木棒,他想把它锯成n段,每段长度分别为L1,L2,...,Ln,问xiaok大佬最少要付给工人多少钱?
输入
第一行两个整数n,L(1<n<103,n<L<109)
第二行n个整数L1,L2,...,Ln(0<Li<L,且保证L1+L2+...+Ln=L)
输出
输出一个整数,表示最小花费
样例输入 Copy
3 21
8 5 8
样例输出 Copy
34
解析:
哈夫曼树的变形,锯下来的每段木头的长度相当于哈夫曼树叶子节点的权值。用锯子锯了i次才把某一段锯下来,说明这一段的长度l会被当做工钱计算了i次。
所以,把n段木头的长度当成n个叶子节点的权值,只需要求出该哈夫曼树的根节点权值,就是最少的花费。
哈夫曼树的构造过程:
只需用优先队列(堆)维护节点权值,每次从中取出最小的两个权值,把他们的和再存入优先队列中,重复n-1次,优先队列中剩下的那个数字就是根节点的权值
代码:
#include<iostream>
#include<queue>
using namespace std;
#define int long long
const int N = 1e3+5;
priority_queue<int,vector<int>,greater<int>> que;//小顶堆
signed main()
{
int n,L;
cin>>n>>L;
for(int i=0;i<n;i++)
{
int t;
cin>>t;
que.push(t);
}
int ans = 0;
for(int i=0;i<n-1;i++)//哈夫曼树有2n-1个节点,其中n个叶子节点,n-1个非叶子节点
{
int a,b;
a = que.top();
que.pop();
b = que.top();
que.pop();
int t = a+b;
ans += t;
que.push(t);
}
cout<<ans;
}