开启掘金成长之旅!这是我参与「掘金日新计划 · 2 月更文挑战」的第 10 天,点击查看活动详情
1.数字组合
给定 个正整数 ,从中选出若干个数,使它们的和为 ,求有多少种选择方案。
输入格式
第一行包含两个整数 和 。
第二行包含 个整数,表示 。
输出格式
包含一个整数,表示可选方案数。
数据范围
,
,
,
答案保证在 范围内。
输入样例:
4 4
1 1 2 2
输出样例:
3
题目分析
这是一道01背包问题。
我们将数字总和 看作背包容量,每个数 看作物品体积。
初始化 ,即总和为 的方案数为 。
Accept代码 O(nm)
#include <bits/stdc++.h>
using namespace std;
const int N = 110, M = 10010;
int a[N], f[M];
int main()
{
int n, m;
cin >> n >> m;
for (int i = 1; i <= n; i ++) cin >> a[i];
f[0] = 1;
for (int i = 1; i <= n; i ++)
for (int j = m; j >= a[i]; j --)
f[j] += f[j - a[i]];
// for (int j = 0; j <= m; j ++) cout << f[j] << "\n "[j < m];
cout << f[m];
return 0;
}
2.货币系统
给你一个 种面值的货币系统,求组成面值为 的货币有多少种方案。
输入格式
第一行,包含两个整数 和 。
接下来 行,每行包含一个整数,表示一种货币的面值。
输出格式
共一行,包含一个整数,表示方案数。
数据范围
输入样例:
3 10
1
2
5
输出样例:
10
题目分析
这是一道完全背包题目。
相较于上题,本题的区别为不再限制单个物品的数量,同样总体积一定。
可以想到用完全背包的方法解决问题,但是本题最终的答案会有一个爆 的情况。
这里留个坑,具体我也不会推导
Accept代码 O(nm)
#include <bits/stdc++.h>
using namespace std;
const int N = 15, M = 3010;
long long a[N], f[M];
int main()
{
int n, m;
cin >> n >> m;
f[0] = 1;
for (int i = 1; i <= n; i ++) cin >> a[i];
for (int i = 1; i <= n; i ++)
for (int j = a[i]; j <= m; j ++)
f[j] += f[j - a[i]];
cout << f[m];
return 0;
}
总结
01背包和完全背包的代码很像,但是两者推导方式大有不同,想要灵活的运用两种算法,建议多进行几次思考与推导,究其本源。