2019年4月10日

总结

虽然讲的进度已经到了区间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。。
就是理论我都知道
但是没有合理的脉络
做题想到哪做到哪
是这种感觉吧。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值