背包DP两杂题(10-10)

131 阅读1分钟

开启掘金成长之旅!这是我参与「掘金日新计划 · 2 月更文挑战」的第 10 天,点击查看活动详情

1.数字组合

给定 NN 个正整数 A1,A2,,ANA1,A2,…,AN,从中选出若干个数,使它们的和为 MM,求有多少种选择方案。

输入格式

第一行包含两个整数 NN 和 MM

第二行包含 NN 个整数,表示 A1,A2,,ANA1,A2,…,AN

输出格式

包含一个整数,表示可选方案数。

数据范围

1N1001≤N≤100,
1M100001≤M≤10000,
1Ai10001≤Ai≤1000,
答案保证在 intint 范围内。

输入样例:

4 4
1 1 2 2

输出样例:

3

题目分析

这是一道01背包问题。

我们将数字总和 MM 看作背包容量,每个数 AiAi 看作物品体积。

初始化 f[0]=1f[0]=1,即总和为 00 的方案数为 11

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.货币系统

给你一个 nn 种面值的货币系统,求组成面值为 mm 的货币有多少种方案。

输入格式

第一行,包含两个整数 nnmm

接下来 nn 行,每行包含一个整数,表示一种货币的面值。

输出格式

共一行,包含一个整数,表示方案数。

数据范围

n15,m3000n≤15,m≤3000

输入样例:

3 10
1
2
5

输出样例:

10

题目分析

这是一道完全背包题目。

相较于上题,本题的区别为不再限制单个物品的数量,同样总体积一定。

可以想到用完全背包的方法解决问题,但是本题最终的答案会有一个爆 intint 的情况。

这里留个坑,具体我也不会推导

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背包和完全背包的代码很像,但是两者推导方式大有不同,想要灵活的运用两种算法,建议多进行几次思考与推导,究其本源。