01背包规划问题

问题:

题目描述:

有一个箱子容量为 V(正整数,0<=V<=20000),同时有 n 个物品(0<n<=30),每个物品有一定的体积和价值。要求 n 个物品中,任取若干个装入箱内,在箱子能放得下的前提下,满足箱子内部的价值最大。

输入描述:

一个整数 v,表示箱子容量

一个整数 n,表示有 n 个物品

接下来 n 个整数,分别表示这 n 个物品的各自体积和价值

样例输入:

3
2
2 100
4 200

样例输出:

100


思考

如果你对01背包规划问题一头雾水的话,那么强烈建议你去看一下这个视频,毕竟,我也是看了视频才写出来的这题,也因此写了笔记来加深映像。北航——算法设计与分析,如果视频下架的话,那么可以去中国大学mooc看,毕竟在B站没版权的视频容易被干掉。

01背包问题的解决方案有3个:

  • 暴力枚举所有可能,递归;
  • 递归,但是采用备忘录,(因为在递归求解问题的过程中,你会发现有很多子问题其实重复了,所以采用备忘录的形式保存这些子问题的答案),用视频里老师的说法是先自顶向下,再自底向上。
  • 动态规划法,直接采用自底向下的方式,省去了自顶向上的过程。

这里采用的动态规划的方法,如果对另外两种方法感兴趣的话,不妨去看一下老师的视频,里面都有涉及,也详细讲解了伪码。

我个人认为,想理解01背包问题首先得理解一张表,以及由那张表所相关得公式。
例子引入:背包容量C =7,物品数量n=4。
w1=5,v1=6 (物品1重量为5,价值为6)
w2=3,v2=5
w3=4,v3=7
w4=2,v4=3

表格的行表示物品的编号,列表示背包的容量,x行y列的值即(x,y)表示在物品编号1-x的物品中,背包容量为y的情况下,背包内装纳物品所能得到的最大价值。
从这个表格的填写过程也能发现自底向上的思想,表格是逐步完善的。表格是一行一行按顺序填写的,而我们想要得到得结果即背包得最大价值也是在填完表格得最后一个空得到得,即最后一行最后一列所对应的值,上图例子的最大价值为12。也是这个填报的过程让我想起了的最短路径问题。

那么这个表是按照什么规律填写的呢?
答案就是我想说的那个公式。请看丑图。

我给的这个公式可能有点小Bug,但是没关系,我可以用文字来堵上这个bug。
那么bug出在哪儿呢?就出在图中画横线的地方,那里可能有时会减出负值出来,如果遇到这种情况,那么最大值就不用判断了,直接采用下面那种情况即可。
这里的bug在代码中是不存在的,之前存在,但被我发现修改掉了。

代码(C++)

点击查看代码
#include <iostream>
#include <algorithm>
using namespace std;
int fun(int *w, int *v, int c, int n); //动态规划
int main()
{
    int c, n; // capacity,num
    while (cin >> c >> n)
    {
        int w[n + 1]; // weight
        int v[n + 1]; // value
        for (int i = 1; i <= n; i++)
        {
            cin >> w[i] >> v[i];
        }
        cout << fun(w, v, c, n) << endl;
    }
    return 0;
}

int fun(int *w, int *v, int c, int n)
{
    int p[n + 1][c + 1] = {0}; //表格
    for (int i = 0; i <= n; i++)
    {
        for (int j = 0; j <= c; j++)
        {
            if (i == 0 || j == 0)
                p[i][j] = 0;
            else if (j < w[i])
                p[i][j] = p[i - 1][j];
            else
                // p[i][j] = (p[i - 1][j] > (p[i - 1][j - w[i]] + v[i])) ? p[i - 1][j] : (p[i - 1][j - w[i]] + v[i]);
                p[i][j] = max(p[i - 1][j], p[i - 1][j - w[i]] + v[i]);
        }
    }
    return p[n][c];
}
posted @ 2022-03-16 22:11  请去看诡秘之主  阅读(113)  评论(0)    收藏  举报