[洛谷]P1090 合并果子(#贪心 -2.2)

题目描述

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

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

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

例如有 33 种果子,数目依次为 11 , 22 , 99 。可以先将 11 、 22 堆合并,新堆数目为 33 ,耗费体力为 33 。接着,将新堆与原先的第三堆合并,又得到新的堆,数目为 1212 ,耗费体力为 1212 。所以多多总共耗费体力 =3+12=15=3+12=15 。可以证明 1515为最小的体力耗费值。

输入输出格式

输入格式:

输入文件 fruit.infruit.in 包括两行,第一行是一个整数 n(1\leq n\leq 10000)n(1n10000) ,表示果子的种类数。第二行包含 nn 个整数,用空格分隔,第 ii 个整数 a_i(1\leq a_i\leq 20000)ai(1ai20000) 是第 ii 种果子的数目。

输出格式:

输出文件 fruit.outfruit.out 包括一行,这一行只包含一个整数,也就是最小的体力耗费值。输入数据保证这个值小于 2^31。2^{31}231 。

思路

这题是一道很好的题目,我现在了解到的就有大约10种方法。一般贪心。[我不会优先队列,堆]。先写下一开始的思路。

法1:要求使用的力气最少,那么就将果子的重量由小到大排序,从最少的两组果子开始堆,并将堆好的果子看成新的一堆,对新数组再排序,再取前两组相加,按照此规则重复进行,最终得到一堆。
说通俗点:先排序,取两个最小的果子相加加入数组,再排序。
这是很容易想到的思路,但是每次都进行排序,会浪费很多时间。下面的法2是一种改进的思想。
法2:先排一遍序,然后顺序查找。排序过后的果子,前2个一定能合并成功,那接下来我把合并好的果子插入这个数组里,覆盖掉原来的果子,再判断大小关系,这种方法效率明显比法1提高不少。
#include <cstdio>
#include <iostream>
#include <algorithm>
#include <math.h>
using namespace std;
int main()
{
	int i,k,n,s=0,a[10002]={};
	scanf("%d",&n);//readline1
	for(i=1;i<=n;i++)
	scanf("%d",&a[i]);//readline2
	sort(a+1,a+n+1);//从小到大排序,便于查找
	for(i=1;i<=n-1;i++)
	{
		a[i+1]+=a[i];//合并,插入到下一个位置
		s=s+a[i+1];//累加至s
		k=i+1;
		while(k<n && a[k]>a[k+1])//如果k<n且前一个元素比后一个元素大
		{
			swap(a[k],a[k+1]);//交换
			k++;//继续遍历
		}
	}
	printf("%d",s);//writeline
	return 0;
}


猜你喜欢

转载自blog.csdn.net/apro1066/article/details/80456127
今日推荐