总结
虽然讲的进度已经到了区间dp了,但是我依然要按着我的进度来整理。
让我们继续搞背包问题。
说实话,脑壳疼。
我不知道是什么原因,我终是绕不过弯子来。
例题
03: 多重背包
有 N种物品和一个容量为 V的背包。第 i 种物品最多有 n[i] 件可用,每件费用
是 c[i] ,价值是 w[i] 。求解将哪些物品装入背包可使这些物品的费用总和不超
过背包容量,且价值总和最大。
首先。根据之前的背包问题,来推导这个的方程的话,其实是很简单的。
f[i][v]=max{f[i-1][v-k*c[i]]+k*w[i]|0<=k<=n[i]}
但是只有一个问题。
会严重超时。
所以我们可以把它转化成01背包问题
比如,有2件价值为5,重量为2的同一物品,我们就可以分为物品a和物品b,a和b的价值都为5,重量都为2,但我们把它们视作不同的物品。
那么解决01背包问题就不需要我再赘述了。
下面我去复制一条代码,看看如何实现
#include <iostream>
using namespace std;
#define V 1000
int weight[50 + 1];
int value[50 + 1];
int num[20 + 1];
int f[V + 1];
int max(int a, int b) {
return a > b ? a : b;
}
int main() {
int n, m;
cout << "请输入物品个数:";
cin >> n;
cout << "请分别输入" << n << "个物品的重量、价值和数量:" << endl;
for (int i = 1; i <= n; i++) {
cin >> weight[i] >> value[i] >> num[i];
}
int k = n + 1;
for (int i = 1; i <= n; i++) {
while (num[i] != 1) {
weight[k] = weight[i];
value[k] = value[i];
k++;
num[i]--;
}
}
cout << "请输入背包容量:";
cin >> m;
for (int i = 1; i <= k; i++) {
for (int j = m; j >= 1; j--) {
if (weight[i] <= j) f[j] = max(f[j], f[j - weight[i]] + value[i]);
}
}
cout << "背包能放的最大价值为:" << f[m] << endl;
}
那么背包问题现在可以大致结束了,其实原则上背包还有一个,不过那个其实就是多种背包混合在一起了,在这里先不搞了。
区间dp
在这里就是简要来一下,具体的整理下次再写。
区间DP主要是把一个大区间拆分成几个小区间,先求小区间的最优值,然后合并起来求大区间的最优值。
//一般区间DP实现代码
memset(dp, 0x3f, sizeof(dp));
for (int i = 1; i <= n; i++) //区间长度为1的初始化
dp[i][i] = 0;
for (int len = 2; len <= n; len++) //枚举区间长度
{
for (int i = 1, j = len; j <= n; i++, j++) //区间[i,j]
{
//DP方程实现
}
}
那么下次进行区间dp的具体整理吧。
感悟
现在脑子中是一团浆糊。
根本不知道用哪个。
或者说。。。
emmmm。。
就是理论我都知道
但是没有合理的脉络
做题想到哪做到哪
是这种感觉吧。