注意事项:
本题是"动态规划—01背包"的扩展题,优化思路不多赘述,dp思路会稍有不同,下面详细讲解。
题目:
给定 N个正整数 A1,A2,…,AN,从中选出若干个数,使它们的和为 M,求有多少种选择方案。
输入格式
第一行包含两个整数 N和 M。
第二行包含 N个整数,表示 A1,A2,…,AN。
输出格式
包含一个整数,表示可选方案数。
数据范围
1≤N≤100,
1≤M≤10000,
1≤Ai≤1000,
答案保证在 int 范围内。
输入:
4 4
1 1 2 2
输出:
3
#include <cmath>
#include <cstring>
#include <iostream>
#include <algorithm>
using namespace std;
const int N = 10010;
int n, m;
int v[N], f[N], s[N][N];
//基础版二维
void base() {
s[0][0] = 1;
for (int i = 1; i<=n; i++) {
for (int j = 0; j<=m; j++) {
s[i][j] += s[i-1][j];
if (j >= v[i]) s[i][j] += s[i-1][j-v[i]];
}
}
cout << s[n][m];
}
//01背包优化,一维滚动数组
void op() {
f[0] = 1;
for (int i = 1; i<=n; i++) {
for (int j = m; j>=0; j--) {
f[j] += f[j-v[i]];
}
}
cout << f[m];
}
int main() {
cin >> n >> m;
for (int i = 1; i<=n; i++) cin >> v[i];
// base();
op();
return 0;
}
思路:
经典的y式dp法
1.状态表示
f[i][j]
: 表示从前i
个数中选,总和刚好为j
的方案,属性为Count。
2.状态计算
以 选择/不选择 第i个物品为划分,
1.当不选择第i个物品时:
f[i][j] += f[i-1][j]
2.当选择第二个物品时:
f[i][j] += f[i-1][j-v[i]]
切记我们这里f[i][j]
中记录的是前i个数中总和为j的方案总数,
是在计算数量,也就是+=。
还有就是初始步骤,f[0][0]
为1,
因为从前0个数中选总和为0也是一种方案。
声明:
算法思路来源为y总,详细请见https://www.acwing.com/
本文仅用作学习记录和交流