最近在补全提高课所有题目的题解,宣传一下汇总的地方提高课题解补全计划
题目描述
一共有 $k$ 种 物品,对于第 $i$ 种物品,第一维 费用 是 $v_{1i}$,第二维 费用 是 $v_{2i}$,价值 是 $w_i$
每个物品只能 被选一次
求一个 选择方案,使得第一维费用 不少于 $n$,第二维费用 不少于 $m$ 且 总价值最小
分析
本题是一个 二维费用01背包问题 ,但和一般的 二维费用01背包问题 不同
这题要求的是 费用不少于 规定条件,因此我们需要对于 状态的定义 进行改变
具体直接参考以下 闫氏DP分析法
初始状态:f[0][j][k]
$\quad 其中~j,k\le 0$
目标状态:f[k][n][m]
Code
时间复杂度: $O(k \times n \times m)$
#include <iostream>
#include <cstring>
using namespace std;
const int N = 1010, M = 85;
int n, m, t;
int v1[N], v2[N], w[N];
int f[M][M];
int main()
{
cin >> n >> m >> t;
for (int i = 1; i <= t; ++ i) cin >> v1[i] >> v2[i] >> w[i];
memset(f, 0x3f, sizeof f); //求最小值要把除初始状态以外的所有状态初始化为+∞
f[0][0] = 0; //这里我们把所有j,k小于0的初始状态都合并到f[0][0][0]中来转移,也就是下面的max操作
for (int i = 1; i <= t; ++ i)
{
for (int j = n; j >= 0; -- j)
{
for (int k = m; k >= 0; -- k)
{
f[j][k] = min(f[j][k], f[max(j - v1[i], 0)][max(k - v2[i], 0)] + w[i]);
}
}
}
cout << f[n][m] << endl;
return 0;
}
分析图里面选第
i
个物品的情况忘记加上第i
个物品的价值了……………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………
你是对的,我帮铅笔大佬改一下:
图里面的集合和属性反了吧
确实是
强!!!
想问下为什么最后不用循环所有方案求最小值呢?(y总一开始的错误代码里面最后循环了一遍的原因是啥
状态转移的时候已经自动min了
两次的状态转移方程表示含义不一样
大佬借个图
Orz
真的牛批
聚聚 当前这个dp的初始化 假设是最最朴素的版本,f[i][[j][k]那种的, 是不是只用初始化f[0][j][k]就可以了?
f[0][0][0] = 0, 其他f[0][j][k]都是INF
应该是的
最朴素的代码是这样的:
为啥初始化其他得要是正无穷因为求的是最小值吗,那如果求最大值得话初始化为0 或者负无穷吗?
分享一下我的看法,DP如果只有一个起点,那除起点外都要初始化,如果任意状态都可以作为起点,则无需初始化。
这也是我dp分析里经常加入初始状态和目标状态的原因
这是我判断是否要初始化状态的根据
然后关于初始化是什么,是题目而定,目的是为了避免非起点的转移影响目标状态的值
巨巨 ,DP如果只有一个起点 是什么意思? 在本题中是指哪个位置?
初始状态:
f[0][j][k]
其中 $j,k≤0$然后这题比较特殊,把所有小于 $0$ 的状态合并到 $0$ 进行转移
所以起点只有
f[0][0]
这种类型的题只能定义为至少吗?为什么不能定义为恰好呢,为什么定义为恰好是错的呢?
可以定义成恰好吧,不过需要注意一些边界问题的处理和状态初始化
好的
这里为什么是j,k”小于“0呢
状态定义中,小于0是有实际意义的