P1090 合并果子 题解
那么,我们开始吧,
堆
堆是一个完全二叉树,而且是每层都有规律的二叉树
规律大概是:
小根堆:最上层数的大小最小,往下每层结点都比父亲结点大,比两个儿子结点小
大根堆:最上层数的大小最大,往下每层结点都比父亲结点小,比两个儿子结点大
题目思路:那么,对于这个题,我们将果子堆sort一下,然后把最小的果堆作为根节点,然后把所有果子堆摞一起,构成一个堆,每次我们只要取堆中最小的两个结点,把他们的和加到体力值消耗总值里面,把这两个结点去掉,然后把他们的和重新加入堆中再维护一下,重复这个过程直到堆中只剩下一个元素,然后输出体力值就ok了
复杂度(nlogn)
安利英语单词:insert 插入,delete 删除,layer(没用到,但是学习一下) 层数,heap 堆
AC代码上菜:
#include<iostream> #include<cstdio> #include<algorithm> #include<cmath> #define ll long long using namespace std; int n,i0,a[10001],k,top1,top2,k2,insert,layer;//layer为层数,insert为插入的节点 ll sum=0; void put(int insert)//将结点插入堆中然后维护的一个函数 { a[++k]=insert;//k为节点个数,入堆之后当然++ int k0=k;//k0为当前此结点的下标 while(k0>1)//此节点不在堆头 { if(a[k0/2]>a[k0])swap(a[k0/2],a[k0]);//如果父亲结点比他大,就交换(大根堆就把大于号改成小于号) else break;//满足小根堆条件,退出 k0/=2;//把它变成父亲结点(在不满足小根堆条件下) } } void delete1(int i)//删除节点+维护操作 { swap(a[i],a[k]); k--;//长度-1,把交换后的原结点值删除 int now=1,nxt,k0=k; while(now*2<=k0) { nxt=now*2; if(nxt<k0&&a[nxt+1]<a[nxt])nxt++; if(a[now]<=a[nxt])break; else swap(a[now],a[nxt]); now=nxt; } } void heap() { while(k>1)//还剩多于两堆水果 { //思路:取出堆中两个最小的节点,然后合并,删除,并重新插入 top1=a[1];insert=a[1];delete1(1); top2=a[1];delete1(1); insert+=top2; sum+=insert; put(insert); } } int main(){ scanf("%d",&n); for(int i=1;i<=n;i++) scanf("%d",&a[i]); sort(a+1,a+1+n);//先排序 k=n;//获取结点个数 heap(); printf("%lld",sum);//输出结果 return 0; }
对大家有帮助吗QWQ
(推荐一个呗。(小声说))