P1090 合并果子

题目描述

在一个果园里,多多已经将所有的果子打了下来,而且按果子的不同种类分成了不同的堆。多多决定把所有的果子合成一堆。

每一次合并,多多可以把两堆果子合并到一起,消耗的体力等于两堆果子的重量之和。可以看出,所有的果子经过 n−1 次合并之后,就只剩下一堆了。多多在合并果子时总共消耗的体力等于每次合并所耗体力之和。

因为还要花大力气把这些果子搬回家,所以多多在合并果子时要尽可能地节省体力。假定每个果子重量都为 1 ,并且已知果子的种类 数和每种果子的数目,你的任务是设计出合并的次序方案,使多多耗费的体力最少,并输出这个最小的体力耗费值。

例如有 3 种果子,数目依次为 1 , 2 , 9 。可以先将 12 堆合并,新堆数目为 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;
}

// 本题的贪心在于如何合并,只有将 果子数最少 的两堆合并才能最省体力值 
// 因为下一次合并用到这堆时,相当于再次将 合成这堆的那两堆 再次移动了 
// 所以只要每次都是将 最少的堆 合并,那么 以后每次移动 都是最省体力值的方式 
// 注意,第一次合并后,不是将第三少的堆和它再次合并,而是重新排序,再挑两个最少的堆合并 
原文地址:https://www.cnblogs.com/go-alltheway/p/13906321.html