您的位置:首页 > 其它

洛谷P1090-合并果子-题解

2016-11-12 22:21 190 查看

合并果子

Hello 大家好,我是CSDN新来的一名……小小的OI选手,刚开通了博客,比较激动233,所以先献上一次题解

那么下面切入正题(为什么不能开头空两个郁闷)

首先献上题目地址

https://www.luogu.org/problem/show?pid=1090

就是这么一道题了,目(keng)测(ding)很多大神都写过,不喜勿喷~

题目分析

很明显的贪心了,每次选两个最小的拿出来求和累加在放回去,直到只剩一堆为止

然后估计所有人一开始看到都是这样想的(手写的有语法错误请谅解哈)

for (int i=1;i<=n;i++) scanf("%d",&a[i]);
do
{ sort(a,a+1+n,cmp);
ans+=(a
+a[n-1]);
a[n-1]+=a
;
n--;
}while (n>1)


然后一看n到10000 我就(zhi zhang)了,于是就引入了神奇的someting



大神肯定司空见惯了,如果有新手的话还是略微解释一下

一棵二叉树,保证根节点一定最优,其两个孩子次优,以此类推

因为是二叉树所以更改和删除都是logn的。

大根堆就是根节点最大,反之亦然

再回到这题,容易发现,可以把n个数建成一个小跟堆,每次用logn的时间取出2个最小值,累加到ans里面,再合并放回去

要做n-1次嘛,每次logn,故复杂度为O(nlogn),也就过了,毕竟1W还是很小的,那么下面献上程序咯

#include <cstdio>
#include <iostream>
#include <cstring>
using namespace std;
int f[10001];
int ans,len,n;
int get()
{
return f[1];
}
void remove()
{
int son,next;
f[1]=f[len--];
son=1;
while (son*2<=len)
{
next=son*2;
if (next<len && f[next+1]<f[next]) next++;
if (f[son]<f[next])break;
swap(f[next],f[son]);
son=next;
}

}
void put(int x)
{
int son,next;
f[++len]=x;
son=len;
while (son>1)
{
next=son>>1;
if (f[son]>=f[next]) break;
swap(f[son],f[next]);
son=next;
}
}
int main()
{
len=0;
scanf("%d",&n);
int x;
memset(f,0,sizeof(f));
for (int i=1;i<=n;i++)
{
scanf("%d",&x);
put(x);
}
ans=0;
while (len>1)
{
int t1=get();
remove();
int t2=get();
remove();
int t3=t1+t2;
//printf("%d %d %d\n",t1,t2,t3);
put(t3);
ans+=t3;
}
printf("%d",ans);
return 0;
}


这道题也就过了,然而是手写堆,比较烦,容易错什么的,于是就有了stl库的优先队列这种interesting的东西,就是满足出队的总是最优,所以就可以写优先队列了,用上stl库,加个头文件

#include <quene>


具体用法抱歉本蒟蒻还没用用过,用过给大家下一题的时候补上

**

谢谢

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