锯木头的花费取决于要锯的那段木头的长度,为了将花费控制到最小,我们自然会想到每次锯的时候尽量让锯出来中较长的一段木头的长度尽可能的短一点,换句话说也就是让锯出来的两段木头的长度尽可能的接近。
题目给的是最终每段木头的长度,反过来想,也就是将木头拼回去,每次花费是两段木头的长度和。那么按照锯木头时的想法,每次拼木头的时候要找两段长度尽可能接近的木头进行拼合,也就是找出最短的两段木头。所以只要用一个优先队列来维护最短的木头长度即可。
我们可以发现,这种做法和哈夫曼树的构造有着惊人的相似之处。其实这道题就是哈夫曼编码应用的一个变型。木头的长度可以视为某个字符出现的次数,出现次数越少的字符在哈夫曼树中的位置就越靠近叶结点。
#include <iostream>
#include <queue>
#include <vector>
using namespace std;
int main()
{
long long ans = 0,x,t1,t2;
int n;
priority_queue<long long, vector<long long>, greater<long long> > q;
cin >> n;
while(n--)
{
cin >> x;
q.push(x);
}
while(q.size()>1)
{
t1 = q.top();
q.pop();
t2 = q.top();
q.pop();
ans += t1 + t2;
q.push(t1 + t2);
}
cout << ans;
return 0;
}