From 5d2b4f9721ba3fc9e6cf26875d30cf18553aac9c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E9=BB=84=E6=B5=B7?= <10402852@qq.com> Date: Wed, 6 Mar 2024 16:42:09 +0800 Subject: [PATCH] 'commit' --- TangDou/AcWing/Bag/278.md | 2 +- TangDou/AcWing/Bag/背包问题专题,md | 64 +++++++++++++++++++++++- 2 files changed, 64 insertions(+), 2 deletions(-) diff --git a/TangDou/AcWing/Bag/278.md b/TangDou/AcWing/Bag/278.md index 36e5153..719b1e8 100644 --- a/TangDou/AcWing/Bag/278.md +++ b/TangDou/AcWing/Bag/278.md @@ -131,7 +131,7 @@ int main() { $A:$我们可以将结论推广到不同属性的情况下,本题的属性是数量,但如果是最大价值呢? 我们不难得到需要将$f[0]$初始化为$0$,$f[1\sim n]$初始化为负无穷 -为什么要这样设置呢?因为每一个新状态,都需要知道它可以从哪些旧状态转移而来,如果上一个状态是合法的,那么有可能从上一个状态转移而来,但如何标识上一个状态是不是合法呢?比如如果初始化状态值是$0$,并且上一个状态是$0$,表示的是目前的最大值,那是不是合法呢?不好说啊,为什么呢? +为什么要这样设置呢?因为每一个新状态,都需要知道它可以从哪些旧状态转移而来,如果上一个状态是合法的,那么有可能从上一个状态转移而来,但如何标识上一个状态是不是合法呢?比如如果初始化状态值是$0$,并且上一个状态是$0$,表示的是目前的最大值,那要是不合法呢?不好说啊,为什么呢? * 上一个状态不合法,没有状态转移过来 * 上一个状态合法,因为有负数等原因,造成最大值确实为$0$ diff --git a/TangDou/AcWing/Bag/背包问题专题,md b/TangDou/AcWing/Bag/背包问题专题,md index 1fe7dd7..2e193bd 100644 --- a/TangDou/AcWing/Bag/背包问题专题,md +++ b/TangDou/AcWing/Bag/背包问题专题,md @@ -109,4 +109,66 @@ int main() { **总结** - $01$背包,还是背一维的形式比较好,一来代码更短,二来空间更省,倒序就完了。 -- 二维费用的$01$背包,简化版本的$01$背包模板就有了用武之地,因为三维数组可能会爆内存。 \ No newline at end of file +- 二维费用的$01$背包,简化版本的$01$背包模板就有了用武之地,因为三维数组可能会爆内存。 + +### 三、$01$背包之恰好装满 +**[$AcWing$ $278$. 数字组合](https://www.acwing.com/problem/content/280/)** + +**二维代码** +```cpp {.line-numbers} +#include + +using namespace std; +const int N = 110; +const int M = 10010; +int n, m; +int v; +int f[N][M]; + +int main() { + cin >> n >> m; + + for (int i = 0; i <= n; i++) f[i][0] = 1; // base case + + for (int i = 1; i <= n; i++) { + cin >> v; + for (int j = 1; j <= m; j++) { + // 从前i-1个物品中选择,装满j这么大的空间,假设方案数是5个 + // 那么,在前i个物品中选择,装满j这么大的空间,方案数最少也是5个 + // 如果第i个物品,可以选择,那么可能使得最终的选择方案数增加 + f[i][j] = f[i - 1][j]; + // 增加多少呢?前序依赖是:f[i - 1][j - v] + if (j >= v) f[i][j] += f[i - 1][j - v]; + } + } + // 输出结果 + printf("%d\n", f[n][m]); + return 0; +} +``` + +**一维代码** +```cpp {.line-numbers} +#include + +using namespace std; +const int N = 10010; + +int n, m; +int v; +int f[N]; // 在前i个物品,体积是j的情况下,恰好装满的方案数 + +int main() { + cin >> n >> m; + + // 体积恰好j, f[0]=1, 其余是0 + f[0] = 1; + for (int i = 1; i <= n; i++) { + cin >> v; + for (int j = m; j >= v; j--) + f[j] += f[j - v]; + } + printf("%d\n", f[m]); + return 0; +} +```