You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

2.8 KiB

This file contains ambiguous Unicode characters!

This file contains ambiguous Unicode characters that may be confused with others in your current locale. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to highlight these characters.

##P5662 [CSP-J2019] 纪念品

前序知识

AcWing 2. 01背包问题

AcWing 3. 完全背包问题

前序练习题

01背包应用 D:\python\TangDou\LanQiao12ShengSai 第四题 农民伯伯种蔬菜

完全背包应用 D:\python\TangDou\LanQiao12GuoSai 小蓝买瓜子

多维限制的完全背包应用 D:/python/LQBS2019/第十届蓝桥杯大赛青少年创意编程C++组省赛(8).pdf

赛瓦维斯特定理+完全背包应用 汤圆组合 D:\python\TangDou\LanQiaoBei13ShengSai_ZJ_II\编程题\3.1.png

算法

稍微一读题,每种纪念品可以买无数次,有总钱数,价格,以及天数,应该都可以想到是完全背包。

总钱数:背包容量;

纪念品价格:每件物品的 价值体积

纪念品数量:物品的种类。

可是到这就又犯难了:纪念品的价格每天都在变,还有手里的钱和纪念品数量在变,还要买或卖,如果都传入状态中,肯定炸空间。

我们一个一个解决:

纪念品的价格尽管每天在变,但题目给出了每天每种的价格。

手里钱、纪念品数以及买卖其实用一个简单的思路就足以解决:我们可以每天早上把手里所有纪念品全部卖掉,获得一天的本金,fufu,如果卖掉了有一些不该卖的,就再买回来,这样相当于每天每件纪念品就只有买或不买,就可以转化为 典型的完全背包,这其实也是一种变相的贪心策略,我们只要保证今天一天的收益最高就行,而不用管后面几天是否能赚最多钱,因为最优情况也被保存在dp数组里,在后面的dp中会被使用并传递。

所以结论是:该背包最重要的状态就是手里的钱,因为它能保存住整体的最优情况在该日的策略,故这题的dp数组可以优化到一维。

不多说,上代码。

#include <bits/stdc++.h>

using namespace std;

const int N = 1010, M = 10010;

int T, n, m;
int f[M];
int w[N][N]; //第i天,第j支股票的价格

int main() {
    scanf("%d%d%d", &T, &n, &m);

    for (int i = 1; i <= T; i++)
        for (int j = 1; j <= n; j++)
            scanf("%d", &w[i][j]);

    //朴素版本
    for (int t = 1; t < T; t++) {              //枚举每一天
        memset(f, 0, sizeof f);                // dp数组
        for (int i = 1; i <= n; i++)           //枚举前i种物品
            for (int j = w[t][i]; j <= m; j++) //枚举剩余体积
                f[j] = max(f[j], f[j - w[t][i]] + w[t + 1][i] - w[t][i]);

        //收益累加
        m += f[m];
    }
    printf("%d\n", m);
    return 0;
}