题目描述
在一个果园里,多多已经将所有的果子打了下来,而且按果子的不同种类分成了不同的堆。多多决定把所有的果子合成一堆。
每一次合并,多多可以把两堆果子合并到一起,消耗的体力等于两堆果子的重量之和。可以看出,所有的果子经过 n−1 次合并之后,就只剩下一堆了。多多在合并果子时总共消耗的体力等于每次合并所耗体力之和。
因为还要花大力气把这些果子搬回家,所以多多在合并果子时要尽可能地节省体力。假定每个果子重量都为 1 ,并且已知果子的种类 数和每种果子的数目,你的任务是设计出合并的次序方案,使多多耗费的体力最少,并输出这个最小的体力耗费值。
例如有 3 种果子,数目依次为 1 , 2 , 9 。可以先将 1 、 2 堆合并,新堆数目为 3 ,耗费体力为 3 。接着,将新堆与原先的第三堆合并,又得到新的堆,数目为 12 ,耗费体力为 12 。所以多多总共耗费体力 3+12=15。可以证明 15 为最小的体力耗费值。
输入格式
共两行。
第一行是一个整数 n (1 ≤ n ≤ 10000)表示果子的种类数。
第二行包含 n 个整数,用空格分隔,第 i 个整数 ai (1 ≤ ai ≤ 20000)是第i种果子的数目
输出格式
一个整数,也就是最小的体力耗费值。输入数据保证这个值小于 2^31 。
输入输出样例
输入 #1
3 1 2 9
输出 #1
15
说明/提示
对于30%的数据,保证有n ≤ 1000
对于50%的数据,保证有n ≤ 5000
对于全部的数据,保证有n ≤ 10000
代码如下
#include<iostream> #include<algorithm> using namespace std; const int MAXN = 10000 + 5; int apple[MAXN]; int main() { int n; // 果子堆数 long long power = 0; // long long !!! cin >> n; for(int i = 1; i <= n; i++) { cin >> apple[i]; } sort(apple + 1, apple + 1 + n); // 按 从少到多 将果子堆排序 int j = 1, m = 0, k = n - 1; while(k--) { m = apple[j] + apple[j + 1]; // m 表示目前果子数最少的两堆果子数之和,即合并两堆要花费的体力值 j++; power = power + m; // 要花费的总体力值 apple[j - 1] = 0; // 两堆合并为一堆后,总堆数少了一个,那么将一个 赋值为 0 apple[j] = m; // 另一个赋值为 m sort(apple + 1, apple + 1 + n); // 因为 m可能比其中某堆大,所以重新排序 } cout << power << endl; return 0; } // 本题的贪心在于如何合并,只有将 果子数最少 的两堆合并才能最省体力值 // 因为下一次合并用到这堆时,相当于再次将 合成这堆的那两堆 再次移动了 // 所以只要每次都是将 最少的堆 合并,那么 以后每次移动 都是最省体力值的方式 // 注意,第一次合并后,不是将第三少的堆和它再次合并,而是重新排序,再挑两个最少的堆合并