合并果子

多多合并果子的问题是一个经典的合并操作优化问题,目标是最小化合并过程中的体力消耗。给定每种果子的数量,需要找出合并的最优顺序,使得总消耗体力最小。例如,当有3种果子,数目分别为1, 2, 9时,最优策略是先合并前两种,然后与第三种合并,总共消耗体力15,这是最小值。" 113579084,10537599,Windows NTLM认证漏洞:风险与防御措施,"['网络安全', 'Windows服务器', '漏洞修复', '身份验证', '安全策略']

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

合并果子

成绩 10 开启时间 2013年03月19日 星期二 14:40
折扣 0.8 折扣时间 2013年03月28日 星期四 14:40
允许迟交 关闭时间 2013年06月30日 星期日 14:40

在一个果园里,多多已经将所有的果子打了下来,而且按果子的不同种类分成了不同的堆。多多决定把所有的果子合成一堆。每一次合并,多多可以把两堆果子合并到一起,消耗的体力等于两堆果子的重量之和。可以看出,所有的果子经过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种果子的数目。

【输出】包括一行,这一行只包含一个整数,也就是最小的体力耗费值。输入数据保证这个值小于231。

  测试输入关于“测试输入”的帮助 期待的输出关于“期待的输出”的帮助 时间限制关于“时间限制”的帮助 内存限制关于“内存限制”的帮助 额外进程关于“{$a} 个额外进程”的帮助
测试用例 1 以文本方式显示
  1. 3↵
  2. 1 2 9↵
以文本方式显示
  1. 15↵
1秒 64M 0

     据说这道题是以前的一个 noip题,这道题用调用stl里面的优先队列可以直接秒杀掉的,看到大家的代码平均行数是37行,大概用的库吧。本着学习的目的查了一些资料,我自己手写了一个最小【堆(优先队列)】,

 首先说一下这道题用到的基本的操作:就是插入和删除,这道题的本质就是 插入和删除一个节点后维护这个完全二叉树的问题。和大家的思路一样插入的时候是把节点插入到最后一个位置然后和父亲节点比较,如果比

父亲节点小,则和父亲节点交换,变成当前节点,然后进行递归操作,直到没有交换。这样插入节点后,就维护了这颗二叉树,时间复杂度为lgn。删除操作就是把堆顶点删除后,把最后一个节点移到堆顶点,然后进行

晒落操作,然后这样就可以完成了删除一个堆顶点后的维护操作。

        当最大堆的时候只不过是判断条件换了一下,其他的操作一样。最大堆是父节点的元素 于子节点的。

       当利用上面的删除和维护操作的时候就可以实现一个堆排序。复杂度为nlgn。还是比较理想的。

       其他的一些小细节是,因为用数组操作的从1开始,所以,每个节点编号x的父亲节点编号是floor(x),其左孩子和右孩子的节点编号为2*x 和 2 * x + 1。还有些注意的是在编代码的时候边界的问题,我就在边界

条件上漏判了结果wa了。

       再说一点其他的吧,我原先使用的一个数组进行降序快排然后进行插入删除,操作来模拟的一个看似像是优先队列的操作,因为以前用这种方法 做过去过一道哈夫曼树的问题, 结果再用到此题中来,结果直接tle了

因为那样做的时间复杂度为N^2lgn。也算成长中的一个小收获吧。呵呵。。那样做也能实现优先队列的操作,但是时间复杂度高了点。没有用二叉树的效率高。要是数据量不是太大的话,还是能过去的。

#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<algorithm>
#define Swap(a,b) a+=b; b = a-b;a -= b
#define Min(a,b) a<b?1:0
using namespace std;


//加入一个节点后维护一棵树;
void insert_node(int *input,int loc)
{

    int parent = loc/2;
    while(parent != 0)
    {
        if(input[parent] <= input[loc])
        {
            break;
        }else{
            Swap(input[parent],input[loc]);
            loc = parent;
            parent /= 2;
        }
    }
    return ;
}


//删除一个节点后,维护一棵树
void del_node(int *input,int n)
{
    int loc = 1,left = 2*loc,right = 2*loc + 1;
    input[loc] = input[n--];
    int t;
    //while(loc < n && left <=n)
    while(left <= n)
    {
        if(right <=n){
            t = Min(input[left],input[right]);
            t = (t== 1)?left:right;
        }else{
            t = left;
        }
        if(input[loc] > input[t])
        {
            Swap(input[loc],input[t]);
            loc = t;
        }else{
            break;
        }
        left = 2 * loc;
        right = 2 * loc + 1;
    }
    return ;
}


int main()
{
    int N;
    int input[10010];
    scanf("%d",&N);

    memset(input,0,sizeof(input));
    for(int i = 1;i < N+1;++i)
    {
        scanf("%d",&input[i]);

        insert_node(input,i);
    }
    long long tmp = 0,s = 0;
    while(N>1)
    {
        tmp = input[1];
        del_node(input,N);
        --N;
        tmp += input[1];
        del_node(input,N);
        input[N] = tmp;
        insert_node(input,N);
        s += tmp;
    }
    printf("%lld\n",s);
    return 0;
}


### 关于蓝桥杯竞赛中的“合并果子”问题 #### 问题描述 在“合并果子”的问题中,给定若干堆果子,每堆果子有一定的重量。可以通过不断将两堆果子合并成一堆来减少果子的数量,直到最终只剩下一堆为止。每次合并的代价等于被合并的两堆果子的重量之和。目标是最小化总的合并代价。 --- #### 解题思路 该问题的核心在于如何通过合理的策略使得总合并代价最小。此问题通常采用 **贪心算法** 来解决,其基本思想如下: 1. 使用优先队列(最小堆)存储每一堆果子的重量。 2. 每次从优先队列中取出权重最小的两个果子堆进行合并,并计算此次合并的代价。 3. 将新合并后的果子堆重新加入优先队列。 4. 不断重复上述过程,直至队列中仅剩下一堆果子。 这种做法能够保证每次都选取当前最轻的两堆果子进行合并,从而尽可能减小后续操作的开销[^2]。 --- #### 算法实现 以下是基于 Python 的具体实现代码: ```python import heapq def merge_fruits(weights): # 初始化最小堆 heapq.heapify(weights) total_cost = 0 while len(weights) > 1: # 取出当前最轻的两堆果子 first_min = heapq.heappop(weights) second_min = heapq.heappop(weights) # 计算本次合并的代价 cost = first_min + second_min # 更新总代价 total_cost += cost # 将新的果子堆放回堆中 heapq.heappush(weights, cost) return total_cost # 测试数据 weights = [1, 2, 3, 4] result = merge_fruits(weights) print(f"最小化的总合并代价为: {result}") ``` --- #### 复杂度分析 - 时间复杂度:由于使用了优先队列(最小堆),每次插入或删除操作的时间复杂度为 \(O(\log n)\),而整个过程中需要执行 \(n-1\) 次合并操作,因此总体时间复杂度为 \(O(n \log n)\)。 - 空间复杂度:主要由优先队列占用的空间决定,空间复杂度为 \(O(n)\)。 --- #### 总结 对于“合并果子”这一类问题,利用贪心算法并通过优先队列优化可以高效求解。需要注意的是,在实际应用中应确保输入数据的有效性和合理性,例如验证是否存在至少两堆果子可供合并。 ---
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值