合并果子(贪心)

题目:合并果子(贪心)

题意:

n堆果子,每次合并可以选择任意两堆合并,每次合并的消耗的体力是这两堆果子的重量和,求把n堆果子合并成1堆所需消耗体力的最小值。

输入格式

输入包括两行,第一行是一个整数 n,表示果子的种类数。

第二行包含 n 个整数,用空格分隔,第 i 个整数 ai 是第 i 种果子的数目。

输出格式

输出包括一行,这一行只包含一个整数,也就是最小的体力耗费值。

输入数据保证这个值小于 2^31

数据范围

1≤n≤10000,
1≤ai≤20000

输入样例:

3

1 2 9

输出样例:

15

样例解释:

第一次合并选择1和2,消耗体力3,第二次合并选择3和9,消耗体力12。总共消耗的体力为3 + 12 = 15。

题目分析:贪心。

解题步骤:

  1. 每次选择序列中最小的两个元素进行合并,序列中添加一个新的元素,即这两个元素的和。
  2. 重复步骤1,直到序列中的元素为1个。

贪心策略证明:

如下图,如果把合并的过程看成一棵树,叶子节点为要合并的果子的数量。可以知道,越先合并的果子的深度越大,权重也会越大。例如下图中,a和b在合并的时候会被加1次,(a + b)和c在合并的时候会被加1次,所以a加了两次,b加了两次,c加了一次。

  1. 设贪心得出的答案是cnt,本题的正确答案是ans。
  2. 由于本题的答案ans是所有合并方案的最小值,所以必有ans <= cnt。
  3. h(x)x在树中的深度,设在正确答案中有c < ah(c) < h(a),则我们可以交换ac的合并顺序,交换不影响其他点的权重。交换后,数值小的点权重变大,数值大的点权重变小,且a和c的权重改变量是相等的,所以交换后能够得到更小的答案。故有cnt <= ans。
  4. 由于ans <= cntcnt <= ans,得cnt = ans。

                      

 

 

AC代码:

#include<iostream>

#include<queue>

 

using namespace std;

 

void solve(){

    int n;

    scanf("%d", &n);

    

    priority_queue<int, vector<int>, greater<int> > pq;

    while(n--){

        int x;

        scanf("%d", &x);

        pq.push(x);

    }

    

    int res = 0;

    while(pq.size() > 1){

        int x = pq.top(); pq.pop();

        int y = pq.top(); pq.pop();

        

        res += x + y;

        pq.push(x + y);

    }

    printf("%d\n", res);

}

 

int main(){

    solve();

    

    return 0;

}

时间复杂度:O(NlogN)。

空间复杂度:O(N)。

posted @   思丶君  阅读(1074)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· 开源Multi-agent AI智能体框架aevatar.ai,欢迎大家贡献代码
· Manus重磅发布:全球首款通用AI代理技术深度解析与实战指南
· 被坑几百块钱后,我竟然真的恢复了删除的微信聊天记录!
· AI技术革命,工作效率10个最佳AI工具
点击右上角即可分享
微信分享提示