最近在补全提高课所有题目的题解,宣传一下汇总的地方提高课题解补全计划
题目描述
给定 $n$ 个正整数:$a_1, a_2, \cdots, a_n$
从中选出若干个数,使得他们的和为 $m$
求最终的 方案数
分析
对于本题我们可以把每个 正整数 看作是一个 物品
正整数 的值就是 物品 的 体积
我们方案选择的 目标 是最终 体积 恰好为 $m$ 时的 方案数
于是本题就变成了 01背包求解方案数 的问题了
闫氏DP分析法
初始状态:f[0][0]
目标状态:f[n][m]
关于 01背包 的详细介绍和各种优化,可以看这篇博客 AcWing 423. 采药【01背包DP模型】
Code
时间复杂度:$O(n \times m)$
#include <iostream>
using namespace std;
const int N = 110, M = 10010;
int n, m;
int v[N];
int f[M];
int main()
{
cin >> n >> m;
for (int i = 1; i <= n; ++ i) cin >> v[i];
f[0] = 1;
for (int i = 1; i <= n; ++ i)
{
for (int j = m; j >= v[i]; -- j)
{
f[j] += f[j - v[i]];
}
}
cout << f[m] << endl;
return 0;
}
Orz
选第i个数应该是:f[i, j] = f[i-1, j] + f[i-1, j-a[i]] 吧?f[j] += f[j-a[i]] 倒是没毛病
不是哦,前者是把选和不选的方案数加起来,小同学可以再思考一下
哦!谢谢
为啥后者通过累加 就可以把 f[m] 即 和为m的方案全部都加到一起啊 抱歉还是不明白。。。。。。。。。
f[ i , j ] = f[ i - 1 , j ] + f[ i - 1 , j - v[ i ] ]
是二维的状态转移方程。一维优化后逆序枚举的f[ j ]
就是二维中的f[ i - 1, j ]
,它加上的f[ j - v[ i ] ]
就是二维中的f[ i - 1 , j - a[ i ] ]
。那请问f【0】 = 0是什么意思呢
f[0] = 1
吗?你看f[0][0]
呀,在前 0 个数选总和恰好为 0 的方法数不是 1 吗。好滴明白啦
不太理解,大佬可以细说一下吗?