|
|
##[$P5662$ [$CSP$-$J2019$] 纪念品](https://www.luogu.com.cn/problem/P5662)
|
|
|
|
|
|
### 前序知识
|
|
|
|
|
|
[$AcWing$ $2$. $01$背包问题](https://www.cnblogs.com/littlehb/p/15366309.html)
|
|
|
|
|
|
[$AcWing$ $3$. 完全背包问题](https://www.cnblogs.com/littlehb/p/15370457.html)
|
|
|
|
|
|
### 前序练习题
|
|
|
|
|
|
$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$数组可以优化到一维。
|
|
|
|
|
|
不多说,上代码。
|
|
|
|
|
|
```cpp {.line-numbers}
|
|
|
#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;
|
|
|
}
|
|
|
``` |