题目描述
有 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即可.
为了方便对照,我写了个输入样例物品价值与容积的表格
目录\编号 | 1 | 2 | 3 | 4 |
V | 1 | 2 | 3 | 4 |
W | 2 | 4 | 4 | 5 |
这个是建立的表格
a\b | 1 | 2 | 3 | 4 | 5 |
1 | 2 | 2 | 2 | 2 | 2 |
2 | 2 | 4 | |||
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;
}