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