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

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

原文地址:https://www.cnblogs.com/lbssxz/p/10776682.html