每日一题~贪心(和贪心磕上了)洛谷1090糖果合并

p1090
一列数,两两合并,每次合并的代价是两堆的和。问将所有的堆合成一堆,最少的代价。
这道题,代码挺容易的。凭借直觉就能ac.(可以很容易的感性的认知到 先进行合并的数,累计的次数次数多。有以下贪心策略)
贪心的策略
将所有的堆放到 优先队列里面。
每次取出最小的两堆合并。
合并之后的新堆,也要push进堆里里面。
之后一直在里面重复取出最小的两堆,在push进去。
直到堆为空。

#include <iostream>
#include <algorithm>
#include <queue>
#include <vector>
#include <map>

using namespace std;

int  main()
{
    std::cin.tie(nullptr)->sync_with_stdio(false);
    int n;cin>>n;
    priority_queue<int,vector<int>,greater<int>>q;int t;
    while(n--)
    {
        cin>>t;
        q.push(t);
    }
    int ans=0;int tt=0;
    while(!q.empty())
    {
        tt=q.top();
        q.pop();tt+=q.top();
        q.pop();
        ans+=tt;
        if(q.size()==0)
        {

        }
        else 
        q.push(tt);
    }
    cout<<ans<<"\n";
    return 0;
}

但是还是有必要认真严谨的去证明贪心的策略正确性。(在b站找到的一个视频
将问题抽象出来。因为是两两合并,可以抽象成一个二叉树。

在这里插入图片描述
每个 节点 代表一个数字堆,当然叶子节点,代表的就是最开始的那一列数(从题目中 读入的数)。
我们可以发现,每一个数字 对结果的贡献就是:这个数*(深度-1).
我们按照 从左往右马,从下往上 的方式去 写出每个数的深度。
可以发现,后面的深度不大于前者(也就是说 深度的排列 是不降的)
所以我们要将小的数安排在前面。
至此贪心的策略证明完成。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值