例如有3种果子,数目依次为1,2,9。可以先将1、2堆合并,新堆数目为3,耗费体力为3。接着,将新堆与原先的第三堆合并,又得到新的堆,数目为12,耗费体力为12。所以多多总共耗费体力=3+12=15。可以证明15为最小的体力耗费值。
输入输出格式
输入格式:
输入文件fruit.in包括两行,第一行是一个整数n(1<=n<=10000),表示果子的种类数。第二行包含n个整数,用空格分隔,第i个整数ai(1<=ai<=20000)是第i种果子的数目。
输出格式:
输出文件fruit.out包括一行,这一行只包含一个整数,也就是最小的体力耗费值。输入数据保证这个值小于2^31。
输入样例
输出样例
说明
对于30%的数据,保证有n<=1000:
对于50%的数据,保证有n<=5000;
对于全部的数据,保证有n<=10000。
此题为贪心。证明如下:
分治来考虑,问题可以划分为子问题 a1<a2<a3的合并顺序。
可以知道合并第二次的和是一样大的,所以只需要让第一次合并和最小,所以要先合并a1,a2。
所以,问题转化为在数组中寻找到第一,第二小的数,合并,放回去,不断重复这个过程。取一次拍一次序必超时,所以考虑使用堆这个数据结构来处理。而用堆,最好使用STL中的优先队列,这样节约考场时间,又不容易出错。
代码如下:
#include
#include
#include
using namespace std;
int n,ans;
priority_queue
,greater
> fruit; int main() { scanf("%d",&n); for(int i=1;i<=n;i++) { int temp; scanf("%d",&temp); fruit.push(temp); } ans=0; for(int i=1;i
我在构造堆时使用了greater仿函数,目的是构造小根堆,因为默认是大根堆。
这里引用洛谷的yyy2015c01 同学的非STL做法,感谢感谢!!!!!
读进数组
排序 取a,b(b开始为空,初始化为近似无穷大,但要使得“无穷大”+“无穷大”=“无穷大”*2,而不会溢出成为负数)
取a,b中最小的两个数合并,存在b数组后面,相加的两个数删掉。这两个数的和累加到体力中。该步重复n-1次。
输出体力
AC*2代码:
#include<cstdio>
#include<cstring>
#include<string>
#include<cmath>
#include<cctype>
#include<iostream>
using namespace std;
int a[100001],b[100000],al=0,ar,bl=0,br=0,tl=0;
void pd()
{
if((a[al]+a[al+1] < a[al]+b[bl])&& (a[al]+a[al+1] < b[bl]+b[bl+1]))
{
b[br]=a[al]+a[al+1];
al+=2;
}
else
{
if (a[al]+b[bl] < b[bl]+b[bl+1])
{
b[br]=a[al]+b[bl];
bl++;
al++;
}
else
{
b[br]=b[bl]+b[bl+1];
bl+=2;
}
}
tl+=b[br];
br++;
}
int main()
{
memset(a,0x3f3f3f3f,sizeof(int)*100001);
memset(b,0x3f3f3f3f,sizeof(int)*100000);
int n;
scanf("%d",&n);
for (int i=0;i<n;i++)
{
scanf("%d",&a[i]);
}
ar=n-1;
int i=1;
bool jh=false;
do
{
jh=false;
for (int j=1;j<=n-i;j++)
{
if (a[j-1]>a[j])
{
a[100000]=a[j-1];
a[j-1]=a[j];
a[j]=a[100000];
jh=true;
}
}
i++;
}
while(jh);
for (int i=1;i<n;i++)
{
pd();
}
printf("%d",tl);
}
祝大家学习愉快,愿OI永葆青春。