您的位置:首页 > 其它

合并果子-----单调队列

2014-05-06 16:33 176 查看
最近在研究单调队列,这题还是比较典型的,我研究了两天(我比较笨。。)刚有些弄懂,就把网上的代码做了一下标注,如果有问题可以进行交流。


题目描述 Description

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

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

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

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


输入描述 Input Description

输入包括两行,第一行是一个整数n(1<=n<=10000),表示果子的种类数。第二行包含n个整数,用空格分隔,第i个整数ai(1<=ai<=20000)是第i种果子的数目。


输出描述 Output Description

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


样例输入 Sample Input

3

1 2 9


样例输出 Sample Output

15


数据范围及提示 Data Size & Hint

对于30%的数据,保证有n<=1000:

对于50%的数据,保证有n<=5000;

对于全部的数据,保证有n<=10000。

解题分析:

对于这道题,首先应该是看的数据,此题数据是n(1<=n<=10000)还有ai(1<=ai<=20000)为了保证程序的运行,这里用long
long(vc++ 6.0编译器不支持这种类型)。然后分析情况,我们要求消耗的体力最小,因此我们最好是把最小的都先依次加起来。

可以设两个数组,一个存放排序后的原数据,一个存放每次相加后的值。对于取之也有几种分析:

1.全部来源于a,此时q为空或者q的队头的元素比a的前两个元素都大.

2.全部来源于b,此时a为空或者a的队头的元素比b的前两个元素都大.

3.a和b中各取一个.

代码如下:

#include<cstdio>

#include<iostream>

#include<iterator>

#include<algorithm> //sort的头文件

#define MAX_N 10009

using namespace std;

int fruit[MAX_N],q[MAX_N];

long long solve(int n)

{

if(n==1) //如果数据剩一个数则不进行比较直接输出

return 0;

long long res = 0,font=0,bck=0,cursor=0;

for(int i=1,temp;i!=n;++i)

{

temp = 0 ;

if(font==bck || (q[font]>=fruit[cursor+1]&&fruit[cursor+1])) //这是第一种情况,当a数组为空,或者q数组的头元素比a数组的前两个都大。时候只能都在a数组里进行挑选

{

temp = fruit[cursor+1] + fruit[cursor] ; //将a数组的前两个元素进行相加

q[bck++] = temp ; //然后加入到q数组的尾部

res += temp ; //将消耗的体力进相加

cursor +=2; //a数组的头向后移动两个,因为刚才取得是两个a数组的元素

}

else if(!fruit[cursor] || (fruit[cursor]>=q[font+1]&&q[font+1]))//这是第二种情况,当q的数组是空的或者a的头比q的前两个元素都大

{

temp = q[font+1] + q[font] ; //将q数组的两个元素相加,

q[bck++] = temp ; //将相加的两个元素的值存入q数组的尾部

res += temp ; //将体力进行相加

font +=2; //头元素指向后两位

}

else

{

temp = q[font++] + fruit[cursor++] ; //第三种情况,去a和q的两个数组的头两个元素,前提是都是最小的进行相加

q[bck++] = temp ; //把相加的和存入到q的尾部

res += temp ; //把体力相加

}

}

return res ; //返回体力值

}

int main()

{

int n ;

scanf("%d",&n);

for(int i=0;i!=n;++i)

scanf("%d",fruit+i); //对输入的n组数据进行存储

sort(fruit,fruit+n); //对存入的无序数据进行升序排序

printf("%lld\n",solve(n)); //输出对应的

return 0;

}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: