合并果子-----单调队列
2014-05-06 16:33
176 查看
最近在研究单调队列,这题还是比较典型的,我研究了两天(我比较笨。。)刚有些弄懂,就把网上的代码做了一下标注,如果有问题可以进行交流。
在一个果园里,多多已经将所有的果子打了下来,而且按果子的不同种类分成了不同的堆。多多决定把所有的果子合成一堆。
每一次合并,多多可以把两堆果子合并到一起,消耗的体力等于两堆果子的重量之和。可以看出,所有的果子经过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。
3
1 2 9
15
对于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;
}
题目描述 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;
}
相关文章推荐
- Luogu1090合并果子[单调队列]
- 合并果子【单调队列】
- 单调队列及其deque写法 HDU 3415+Poj 4002 (日期处理) + 合并果子
- 合并果子 单调队列的模板题
- TYVJ 1066 合并果子【优先队列】
- NOIP提高组2004 合并果子(优先队列排序)
- 07年 ZZUPC校赛第三题 合并果子(优先队列 ~)
- 【算法学习笔记】79.STL 优先队列 模拟法 SJTU OJ 4012 合并果子
- 洛谷P1090 合并果子 (优先队列伪STL)
- 【双队列】【NOIP2004提高组】二、合并果子
- Vijos P1097 合并果子(优先队列 贪心)
- Luogu 1090 合并果子(贪心,优先队列,STL运用)
- 二叉堆&优先队列-----noip2004 合并果子
- Vijos-P1097-合并果子(简单贪心 && 优先队列 && c++)
- 优先队列 合并果子通俗易懂
- 树-堆结构练习——合并果子之哈夫曼树(其实是优先队列)
- STL 优先队列-- 树-堆结构练习——合并果子之哈夫曼树
- 合并果子(优先队列 +或者+哈夫曼)
- 1270 药不能停(合并果子,优先队列,堆)
- 1063 合并果子 优先队列