总结背包问题的至多/恰好/至少

Posted 蒟蒻豆进阶之路

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了总结背包问题的至多/恰好/至少相关的知识,希望对你有一定的参考价值。

对于一维背包问题,注意区分该问题的下面这三种情况,即至多/恰好/至少,它们的状态转移方程其实是一样的差异在于初始化

一、体积至多是v时的最小/大值

这是背包问题中最常见的问法,取最小用\\(min\\),取最大用\\(max\\)

方法:全部初始化为\\(0\\),且保证\\(v\\)大于等于\\(0\\)
代表题目:\\(AcWing\\) \\(423\\) .采药,其代码如下:

#include<bits/stdc++.h>

using namespace std;
const int N = 1010;

int n, m;
int v[N], w[N];
int f[N];

int main() 
    //优化输入
    ios::sync_with_stdio(false);
    //物品个数n
    cin >> m >> n;
    //读入体积和重量
    for (int i = 1; i <= n; i++) cin >> v[i] >> w[i];
    //01背包模板
    for (int i = 1; i <= n; i++)
        for (int j = m; j >= v[i]; j--)
            f[j] = max(f[j], f[j - v[i]] + w[i]);

    cout << f[m] << endl;
    return 0;

二、 体积恰好是v时的最小/大值

方法:\\(f[0]\\)初始化为\\(0\\),其余初始化为正/负无穷(分别对应题目问的最小/最大,代表不合法状态,不应该被选取),且保证\\(v\\)大于等于\\(0\\)

代表题目:LeetCode 322.零钱兑换,其代码如下:

三、 体积至少是v时的最小/大值

方法:\\(f[0]\\)初始化为\\(0\\),其余初始化为正/负无穷(分别对应题目问的最小/最大,代表不合法状态,不应该被选取),无需保证\\(v\\)大于等于\\(0\\)
代表题目:\\(AcWing\\) \\(1020\\).潜水员,其代码如下:

#include <bits/stdc++.h>

using namespace std;
const int N = 1010; //气缸的个数上限
const int M = 100;  //需要的氧气、氮气上限值

int V1; //氧需要的量
int V2; //氮需要的量
int n;  //气缸的个数

int v1[N], v2[N], w[N];//第i个气缸里的氧和氮的容量及气缸重量
int f[M][M]; //DP数组

int main() 
    //读入氧需要的量,氮需要的量,气缸的个数
    cin >> V1 >> V2 >> n;
    //读入每个气缸的氧和氮的容量及气缸重量
    for (int i = 1; i <= n; i++) cin >> v1[i] >> v2[i] >> w[i];
    //求最小值要把除初始状态以外的所有状态初始化为+∞
    memset(f, 0x3f, sizeof f);
    f[0][0] = 0;
    //因为采用了降维,所以体积都是倒着的~
    for (int i = 1; i <= n; i++)
        for (int j = V1; j >= 0; j--)
            for (int k = V2; k >= 0; k--)
                f[j][k] = min(f[j][k], f[max(j - v1[i], 0)][max(k - v2[i], 0)] + w[i]);
    //输出
    printf("%d", f[V1][V2]);
    return 0;

以上是关于总结背包问题的至多/恰好/至少的主要内容,如果未能解决你的问题,请参考以下文章

Luogu6478 游戏

#yyds干货盘点# 动态规划专题:完全背包

基础背包

[DP] 背包问题大总结

hdu 3535 分组背包

背包恰好装满和不必装满的初始化区别