题解 P1090 【合并果子】
证明不断取最小的两堆合并成较大的一堆是最优的。
(不太好证哦)
①最优方案可以表示成一个二叉树。总代价
注意:
②最小的两堆一定在最优方案树的最深层。
这个用反证法。假设有一个最优方案树,其最深层中没有最小的两堆。那么把最小的堆与最深层的某堆互换位置形成新方案,保证新方案存在而且新方案的代价小于原方案。
注意:最深层总是一组(一组有两个)或多组叶子节点,来表示它们被直接合并。
③同层叶子节点互换,对总代价无影响。
根据①的
④根据上两步,我们已经明确:最优方案需要直接合并当前最小的两堆。现在我们就进行这个操作。事实是:现在只剩
注意:这并不意味着之前一步的操作使日后的代价和非常优秀。
#include <cstdio>
#include <queue>
using std :: priority_queue;
using std :: greater;
using std :: vector;
int n, ans = 0;
priority_queue < int, vector <int>, greater <int> > q;
int main()
{
scanf("%d", &n);
for(int i = 1; i <= n; ++i)
{
int x; scanf("%d", &x);
q.push(x);
}
while(q.size() > 1)
{
int x = q.top(); q.pop();
int y = q.top(); q.pop();
ans += x + y;
q.push(x + y);
}
printf("%d\n", ans);
return 0;
}
这些说法是不对的:
一、每步取最小的两堆合并成较大的两堆,能保证形成“这一步代价最小”且“接下来将要消耗的代价比其它方案小”。
反例如,如果有四堆果子,数目分别是
二、如果给初始的每堆果子
其实方案不同的时候,
这道题可视作构造哈夫曼树。而对哈夫曼树正确性的证明让很多人头疼,《Algorithms》也是大花笔墨!所以证明可能真的不是那么简单。
有更简单的证明、或者上面的证明有问题,就评论吧!