P1090 合并果子 题解

时间:2024-03-31 08:33:20

那么,我们开始吧,

堆是一个完全二叉树,而且是每层都有规律的二叉树

规律大概是:

小根堆:最上层数的大小最小,往下每层结点都比父亲结点大,比两个儿子结点小

大根堆:最上层数的大小最大,往下每层结点都比父亲结点小,比两个儿子结点大

题目思路:那么,对于这个题,我们将果子堆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[],k,top1,top2,k2,insert,layer;//layer为层数,insert为插入的节点
ll sum=;
void put(int insert)//将结点插入堆中然后维护的一个函数
{
a[++k]=insert;//k为节点个数,入堆之后当然++
int k0=k;//k0为当前此结点的下标
while(k0>)//此节点不在堆头
{
if(a[k0/]>a[k0])swap(a[k0/],a[k0]);//如果父亲结点比他大,就交换(大根堆就把大于号改成小于号)
else break;//满足小根堆条件,退出
k0/=;//把它变成父亲结点(在不满足小根堆条件下)
}
}
void delete1(int i)//删除节点+维护操作
{
swap(a[i],a[k]);
k--;//长度-1,把交换后的原结点值删除
int now=,nxt,k0=k;
while(now*<=k0)
{
nxt=now*;
if(nxt<k0&&a[nxt+]<a[nxt])nxt++;
if(a[now]<=a[nxt])break;
else swap(a[now],a[nxt]);
now=nxt;
}
}
void heap()
{
while(k>)//还剩多于两堆水果
{
//思路:取出堆中两个最小的节点,然后合并,删除,并重新插入
top1=a[];insert=a[];delete1();
top2=a[];delete1(); insert+=top2;
sum+=insert;
put(insert);
}
}
int main(){
scanf("%d",&n);
for(int i=;i<=n;i++)
scanf("%d",&a[i]);
sort(a+,a++n);//先排序
k=n;//获取结点个数
heap();
printf("%lld",sum);//输出结果
return ;
}

对大家有帮助吗QWQ

推荐一个呗。(小声说))