蓝桥杯习题ACwing

https://www.acwing.com/problem/content/description/5293/

解析:
// 证明 haffman 为什么是正确的,每一次为什么可以得到最优解?  
// 首先,证明为什么每次合并叶子节点的一对是最优解
// 1.如果两个节点是在同一层 && 两个叶子节点不在同一个根节点下,那么由于是同一层,所以交换两个节点的位置,结果一定不会变差
// 2.如果两个节点不在同一层 ,假设 y > z ,dy > dz
// 合并后 res = y * dy + z * dz;
// 那么如果交换 y 和 z 的位置
// res1 = z * dy + y * dz
// res - res1 = dy * (y - z) - (y - z) * dz
// ans = res - res1 = (y - z) * (dy - dz) 
// 由于 y > z && dy > dz ,所以 ans > 0 , 所以说res > res1 ,也就是说交换后的结果会变得更优
// 所以将权重比较大的节点放到距离根节点比较近的距离更好 

// 处理合并两堆还是三堆的问题?
// 如果合并两队,如果1 , 2 两对叶子节点在同一层,那么将2中的一个与 1 的两个合并为 3个
// 一定不会使结果变差 , 从而将 2 中的另一个合并到其父节点的父结点上,从而使层数减一,值变小
// 所以综合来讲 ,一定会比当前的解更优
// 如果 1 , 2 两对叶子节点不在同一层 d2 > d1 , 那么同上面一样的方法 ,一定会使 2 中的一个节点合并到 1 中
// 并将当前 2 中剩余的节点合并到其父节点的父节点上去 ,一定不会使结果变得更差
// 所以综上所述 ,合并 3 堆一定合并两堆更好 

代码:

#include <iostream>
#include <cstring>
#include <algorithm>
#include <queue>

using namespace std;

typedef long long LL;

const int N = 2e5 + 10;

int main()
{
    int n;
    cin >> n;
    
    priority_queue<LL , vector<LL> , greater<LL>> heap;
    
    for(int i = 0 ; i < n ; i ++)
    {
        int x;
        cin >> x;
        heap.push(x);
    }
    
    if(n % 2 == 0) heap.push(0);
    
    LL cost = 0;
    while(heap.size() > 1)
    {
        LL sum = 0;
        for(int i = 0 ; i < 3 ; i ++)
        {
            LL x = heap.top();
            heap.pop();
            sum += x;
        }
        heap.push(sum);
        cost += sum;
    }
    
    cout << cost << endl;
    
    return 0;
}
 

  • 9
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值