动态规划--最简单的01背包问题

题目描述

有 N件物品和一个容量是 V 的背包。每件物品只能使用一次。

第 ii 件物品的体积是 vi,价值是 wi。

求解将哪些物品装入背包,可使这些物品的总体积不超过背包容量,且总价值最大。
输出最大价值。

输入格式

第一行两个整数N,V,用空格隔开,分别表示物品数量和背包容积。

接下来有 N 行,每行两个整数 vi,wi,用空格隔开,分别表示第 i 件物品的体积和价值。

输出格式

输出一个整数,表示最大价值

数据范围

0<N,V≤10000
0<vi,wi≤1000

输入样例

4 5
1 2
2 4
3 4
4 5

输出样例

8

这里介绍新手比较容易理解的方法,建立一个二维数组

我们定义一个数组sum[a][b],表示只计算前a件物品,背包容积为b时的最优解

如此可以建立关于数组sum的表格,这里以输入样例为例子,共有四个物品,那么我们a<=4即可

容积为5,那么b<=5即可.

为了方便对照,我写了个输入样例物品价值与容积的表格

目录\编号1234
V1234
W2445

这个是建立的表格

a\b12345
122222
224
3
4

由此看,以(a,b)的格式看,(a,b)代表的就是取前a件物品,当背包容积为b时可取到的最大价值

填写表格的部分可以跳过直接看核心代码,一直到下面的代码块(因为太麻烦了,我自己都不确定写没写的清楚)

接下来我们来尝试填写表格

(1,1),只看第一件物品,他的体积为1,价值为2,我们的背包容积刚好为1,所以,(1,1)填2;

(1,2),只看第一件物品,背包容积为2,背包容积余1,但是没有物品了,仍然写2;

(1,n)同理

(2,n),只看前2件物品;

(2,1),第一件,背包容积大于物品体积,sum[2][1]=sum[1][1],再看下一件,这个时候我们的空余背包容积为0,此时背包里面有一件体积为1,的物品,而第二件物品的容积为2,即使去掉第一件物品也装不下,由此可知,sum[2][1]=sum[1][1];

(2,2),还是先装下第一件,到了第二件的时候发生了不同,如果我们将第一件物品拿出来,就可以放下第二件,而且第二件如此的话,他的价值反而高,所以我们是怎么来算出sum的, 先放进去第一件,然后比较发现空出第二件的空间来放第二件总价值更高  sum[2][2]=sum[2-1][2-v[2]]+w[2];我们是要回溯一下,前面求的倒出空间后的最优解,加上这个物品的价值,就是这种装法的结果价值

这里是当总空间大于这个物体,而目前容积装不下时,我们可以有两个选择,A腾出空间装下,和B不装下这个物体,

(A)我们是要回溯一下,找到前面刚好导出空间时的最优解,加上这个物体的价值,就是我们要求的这个选择的结果sum[a-1][b-v[2]]+w[2];

(B)选择不装下这个物体,就简单了,就等于a轴坐标向上移动一格,sum[a][b]=sum[a-1][b];

我们要要价值最大也就是sum[a][b] = Max(sum[a - 1][b], sum[a - 1][b - v[a]] + w[a]);

所以,总结出的公式

sum[a][b] = Max(sum[a - 1][b], sum[a - 1][b - v[a]] + w[a])

由此,可以大体的写出那部分的代码块

for (int i = ; i <=a ; i++)
	{
		for (int j = 1; j <= b; j++)
		{
			if (j > v[i])sum[i][j] = sum[i-1][j]+w[i];
			else
			{
				sum[i][j]=max(sum[i - 1][j], sum[i - 1][j - v[i]] + w[i])
			}
		}
	}

这里贴一下代码


#include <iostream>

using namespace std;

const int N = 1005;

int n, m;
int w[N];
int v[N];
int sum[N][N];

int main()
{
    cin >> n >> m;
    for (int i = 1; i <= n; i++) cin >> w[i] >> v[i];
    for (int i = 0; i < n; i++)
    {
        for (int j = 0; j <= m; j++)
        {
            sum[i + 1][j] = max(sum[i + 1][j], sum[i][j]);
            if (j + w[i + 1] <= m)sum[i + 1][j + w[i + 1]] = max(sum[i + 1][j + w[i + 1]], sum[i][j] + v[i + 1]);
        }
    }
    cout << sum[n][m];
    return 0;
}

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值