AcWing 278. 数字组合
题目
给你 n 个数,让你从中选出一些数,使其和为 m,问一共有多少方案?
n <= 100, m <= 10000
分析
简单的背包问题。看成背包容量为 m,n 个物品。
①:状态表示
- 集合: d p [ i ] [ j ] dp[i][j] dp[i][j] 表示用前 i 个数,和为 j 的所有方案的集合
- 属性:方案的数量
②:状态转移
根据最后一位来划分集合,选还是不选?
不选:
d
p
[
i
]
[
j
]
+
=
d
p
[
i
−
1
]
[
j
]
dp[i][j] += dp[i - 1][j]
dp[i][j]+=dp[i−1][j]
选:
d
p
[
i
]
[
j
]
+
=
d
p
[
i
−
1
]
[
j
−
v
]
dp[i][j] += dp[i-1][j-v]
dp[i][j]+=dp[i−1][j−v]
这道题还可以用滚动数组优化。
#include <bits/stdc++.h>
using namespace std;
#define db(x) cout<<x<<endl
typedef long long ll;
const int INF = 0x3f3f3f3f;
const int N = 1e4 + 10;
const int M = 1e2 + 10;
const ll mod = 998244353;
int n, m;
int a[M], dp[M][N];
int main() {
scanf("%d%d", &n, &m);
for (int i = 1; i <= n; i++) {
scanf("%d", &a[i]);
}
for (int i = 0; i <= n; i++) dp[i][0] = 1;
for (int i = 1; i <= n; i++) {
for (int j = 1; j <= m; j++) {
dp[i][j] = dp[i - 1][j];
if (j >= a[i]) dp[i][j] += dp[i - 1][j - a[i]];
}
}
printf("%d\n", dp[n][m]);
return 0;
}
滚动数组优化:
#include <bits/stdc++.h>
using namespace std;
#define db(x) cout<<x<<endl
typedef long long ll;
const int INF = 0x3f3f3f3f;
const int N = 1e4 + 10;
const int M = 1e2 + 10;
const ll mod = 998244353;
int n, m;
int dp[N];
int main() {
scanf("%d%d", &n, &m);
dp[0] = 1;
for (int i = 1, v; i <= n; i++) {
scanf("%d", &v);
for (int j = m; j >= v; j--) {
dp[j] += dp[j - v];
}
}
printf("%d\n", dp[m]);
return 0;
}