NYG的背包 (贪心)

本文详细解析了一道背包问题的贪心算法解决方案,重点介绍了如何根据物品的属性进行排序以实现最优放置策略。通过具体实例说明了正负贡献值物品的不同处理方式,并强调了在设计贪心策略时的思考过程及反例验证的重要性。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

9.19

题解

#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
#define LL long long
using namespace std;

const int N = 1e5+4, INF = 0x3f3f3f3f;

struct Node {
    LL aa, bb, cc;
    friend bool operator <(const Node &p, const Node &q) {
        if(p.cc>=0 && q.cc>=0) return p.aa < q.aa;
        if(p.cc<0 && q.cc<0) return p.bb > q.bb;
        return p.cc>=0;
    }
}aa[N];

int n,T;
LL V;

inline int read() {
    int x=0; char cc=getchar();
    while (cc<'0'||cc>'9') cc=getchar();
    while (cc>='0'&&cc<='9') x=x*10+cc-'0',cc=getchar();
    return x;
}

int main() {
    freopen("backpack.in","r",stdin);
    freopen("backpack.out","w",stdout);
    T = read();
    while (T--) {
        n = read(), V = read();
        for(register int i=1; i<=n; ++i)
            aa[i].aa = read(), aa[i].bb = read(), aa[i].cc = aa[i].bb - aa[i].aa;
        sort(aa+1, aa+n+1);
        bool flag = true;
        for(register int i=1; i<=n; ++i) {
            if(V < aa[i].aa) {flag = false; break;}
            V += aa[i].cc;
        }
        puts(flag ? "Yes" : "No");
    }
    return 0;
}

此题很有复习价值,本题中有几个点重点:

【1】 对于可行问题要往贪心方向思考

【2】 在想贪心方案是需要严格证明,宁可画上一定时间(但要控制再半小时以内)去证明正确性 , 找反例

【3】 在想贪心情况时 , 要落到实处 ,若觉得一个策略不对则需要通过题目特性落到实处看其是否正确;找反例时先感性想想反例出现情况,在去构造对应数据看是否能否定当前结论

在解决此题时 , 由于放入体积与增加体积,而且题目问题是是否可解,可使人想到贪心;

而贪心策略中,由于要是其放得下,所以可以想到先放有贡献(增加体积)的情况 , 然后猜测是贪心顺序,以a排序?b排序?还是b-a?此时发现它最后加完的体积是一个定值 , 而其体积也在不断增加,那么应该是a越大的放到越后面能跟保险的放下,然而是否会有反例,根据其特性:v会应为b - a > 0 而不断增大,显而易见策略正确;

而此题头疼的是b - a < 0 时的策略 : 还是按照上面所述的思路 , a?,b?,b-a?,按照从大到小?从小到大?貌似从正面不好想,但有个性质时确定的:

最后的体积为定值

那么从次特性思考,倒着来想:
最后的状态是:

V + b1 + b2 + b3 + … + bn >= a1 + a2 + a3 + … + an

那么最后一次选择便是选择先将左式减去对于的b , 在不等式成立的情况下在减去对应得a ,由于后面加上的是b - a < 0 , 那么每次减去一组对应的a,b时左式减右式的值会越来越大 , 所以只要保证每次删的b最小,时左式减小的尽量少,那么等式则月容易成立,所以嘛。。。反过来想 , 不就是。。。以b为标准从大到小排序。。。
那么全程的贪心策略则出来了:
对于 a - b > 0 的情况 以a为标准从小到大排序
对于 a - b < 0 的情况 以b为标准从大到小排序

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值