• 【AcWing题解/Google Kickstart2019 Round B Problem B】能量石


    原题链接:https://www.acwing.com/problem/content/description/736/
    难度:困难(?)
    涉及知识点:01背包、贪心算法

    题意分析

    给定一些能量石,对于第 i i i 块能量石,其初始能量值为 E i E_i Ei,每秒会减少 L i L_i Li 单位的能量,吃完这块能量石需要 S i S_i Si 秒并且会立刻得到这块能量石的能量。能量石的的能量最多降到 0,不会为负数。求杜达最后能获得多少能量。

    分析与解决

    这一题乍一看确实是没有思路的,但是我们细想一下,在基于闫氏DP思考法即在集合角度思考DP 问题时,往往是考虑了整个集合,那么存不存在一个子集,让我们的注意力都集中在某一个子集中呢?当然有,这个子集就是最优解子集
    考虑在最优解子集 a a a 中, 元素的排列为
    a 1 , a 2 , a 3 , a 4 , a 5 , . . . , a n − 2 , a n − 1 , a n a_1,a_2,a_3,a_4,a_5,...,a_{n-2},a_{n-1},a_n a1,a2,a3,a4,a5,...,an2,an1,an
    对于一组相邻的元素 a i a_i ai a j a_j aj,如果我先吃 a i a_i ai 再吃 a j a_j aj,那么所获取的能量为 E i + E j − S i × L j E_i+E_j-S_i\times L_j Ei+EjSi×Lj;反之所获得的能量为 E j + E i − S j × L i E_j+E_i-S_j\times L_i Ej+EiSj×Li,由于这是最优解子集,我们必然可以得出如下不等式
    E i + E j − S i × L j ≥ E j + E i − S j × L i ① E_i+E_j-S_i\times L_j\geq E_j+E_i-S_j\times L_i① Ei+EjSi×LjEj+EiSj×Li
    整理得
    S i × L j ≤ S j × L i ② S_i\times L_j\leq S_j\times L_i ② Si×LjSj×Li
    逆向推理,也就是如果一个集合能够满足这两个不等式,就一定是最优解子集,那么我们就可以在输入数据出通过 s o r t sort sort 排序构造出最优解子集。然后在最优解子集里做 01 背包即可。

    AC代码

    #include 
    #include 
    #include 
    #include 
    
    using namespace std;
    
    const int N = 1e4 + 10;
    
    struct Stone
    {
        int s, e, l;
        bool operator< (const Stone &W) const
        {
            return s * W.l < l * W.s;
        }
    }stone[N];
    int T, n;
    int f[N];
    
    int main()
    {
        cin >> T;
        
        for (int C = 1; C <= T; C++)
        {
            int m = 0;
            cin >> n;
            for (int i = 1; i <= n; i++)
            {
                int s, e, l;
                cin >> s >> e >> l;
                stone[i] = {s, e, l};
                m += s;
            }
            
            sort(stone + 1, stone + n + 1);
            
            memset(f, -0x3f3f3f3f, sizeof f);
            f[0] = 0;
            
            for (int i = 1; i <= n; i++)
            {
                int s = stone[i].s, e = stone[i].e, l = stone[i].l;
                for (int j = m; j >= s; j--)
                {
                    f[j] = max(f[j], f[j - s] + e - (j - s) * l);
                }
            }
            
            int res = 0;
            for (int i = 0; i <= m; i++) res = max(res, f[i]);
            printf("Case #%d: %d\n", C, res);
        }
        return 0;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
  • 相关阅读:
    JAVA计算机毕业设计医院管理系统Mybatis+源码+数据库+lw文档+系统+调试部署
    002-JAVA的数据类型,变量声明与定义
    前端根据后端返回的数组对象处理转为树状结构
    记录一次对某网站的sql注入
    LeetCode 2512. 奖励最顶尖的 K 名学生:哈希表设计
    【http协议】Content-Type 超详细介绍
    Uboot
    某公路边坡支护设计(lunwen+计算书+cad图纸+施工组织设计)
    ruby、Python 以及 Swift 语言关于 “Finally” 实现的趣谈
    微信小程序之本地生活(九宫格)
  • 原文地址:https://blog.csdn.net/lightningcs/article/details/126436207