洛谷-合并果子(P1090)

本文探讨了一种使用哈夫曼树解决果子合并问题的算法,通过升序排序和优化的插入排序策略,实现了最小化搬运果子所耗费体力的目标。文章详细解释了算法思路和步骤,并提供了C++代码示例。
题目链接:

合并果子

问题分析:

根据题目描述,不禁让我们想到了哈夫曼树。每次从森林中选取两棵权值较小的子树,通过合并再放入森林(相应的两棵子树应从森林中删去),直至森林中仅含有一棵树。本题要求每次合并两堆果子,直至合成一堆。并且要求浪费的体里最少(果子多的堆花费的力气多)。
问题最优解即花费的力气最少,也就要求将数量少的堆向大的堆移动。数量越大的堆,搬动的次数越少,不也就花费的力气越少嘛。

问题求解:
  1. 输入初始每堆果子数量,且升序排序(优先移动数量少的果子)
  2. 合并数量最少的两堆果子,并且下次仍需要选取最少的两堆
  3. 直至仅剩唯一一堆果子

即每次在一堆中找其中数量最少的两堆。思路很简单,每次合并完最少的两堆,再将合并后的排一次序不就可以了吗?但是测试会超时。
有了求解的思路,每次将合并后的再次排下序,则不难求出问题的解。
因为已经经过了第一次sort排序,序列已基本有序。因此这题的解题思路可以向希尔排序上靠,希尔排序提高效率的方法是减少待比较序列比较数量以及使序列基本有序。因此这题我们可以借助插入排序,每次合并完,将合并后的果子放入序列中的合适位置。

代码示例:
#include<iostream>
#include<algorithm>
using namespace std;

int main(){
 	int n, sum = 0;
 	cin >> n;
 	int wt[n];
 	for(int i = 0; i < n; i++){
  		cin >> wt[i];
 	}
 	sort(wt, wt+n);
 	for(int i = 1, j; i < n; i++){
  		wt[i] += wt[i-1];
  		wt[0] = wt[i];
  		for(j = i+1; j < n && wt[j] < wt[0]; j++){
   			wt[j-1] = wt[j];
  		}
  		wt[j-1] = wt[0];
  		sum += wt[0];
	}
 	cout << sum;
 	return 0;
}

因为经过了第一次的sort排序,序列基本有序,所以插入排序的时间复杂度是可观的,也就不会造成测试超时问题。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值