01背包问题
题目
一个旅行者有一个最多能用m公斤的背包,现在有n件物品,它们的重量分别是W1,W2,…,Wn,它们的价值分别为C1,C2,…,Cn.若每种物品只有一件求旅行者能获得最大总价值。
输入
第1行:两个整数,M(背包容量,M<=200)和N(物品数量,N<=30);
第2至N+1行:每行二个整数Wi,Ci,表示每个物品的重量和价值。
输入样例
10 4
2 1
3 3
4 5
7 9
输出
仅一行,一个数,表示最大总价值。
输出样例
12
思路
首先我们将这个总共的最大价值要求理解一下,这个总最大价值取决于之前每一步的最大价值,每一次物品是否放入的选择就是要判断,当它放入或者不放的时候前面的包内的最大价值,如果放入的话,就要考虑总容量减去这个物品质量之后的最大价值与现在这个物品的最大价值之和,还要考虑这件物品不放入时包内容量的最大价值,将这两种情况作比较,取最大价值。
给出以下方程:
dp[i][j] = max { dp[i-1][j-t[i]] + v[i], dp[i-1][j] };
再来解释一下这个方程:
① dp[i][j]指的是前i件物品放入容量为j的背包中时最大价值;
② dp[i-1][j-t[i]]指的是当将第i件物品放入时背包容量变成了j-t[i]时前i-1件物品所取得的最大价值,那么dp[i-1][j-t[i]] + v[i]指的是第i件物品放入时的前i件物品放入容量为j的背包时的最大价值;
③ dp[i-1[j]指的是当第i件物品不放入背包时背包容量依旧是j,考虑前i-1件物品放入背包中的最大价值;
比较这两种情况得到其中获得的最大价值,那么这就是前i件物品放入容量为j的背包时的最大价值。
最后一次的最大价值,要去考虑之前的最大价值,那么对于每次这样的考虑就可以认为是我们需要知道每次dp[i-1][j-t[i]]的最大价值,即在每次对于物品的存放时都要更新除去当前物品质量的背包容量下的最大价值,用[j-t[i]]去找已经存入的最大价值,再与v[i]相加后和dp[i-1][j]作比较。所以有必要建立一个长度大于背包容量的数组,下标表示的是当前的容量,这个单位表示的就是在这容量下的最大价值,每次循环都会更新当前容量的最大价值。
代码
#include<cstdio>
#include<iostream>
using namespace std;
int t,m,a[1001],f[1001],g[1001]; //初始化
int main()
{
scanf("%d%d",&t,&m);//读入
for (int i=1;i<=m;i++)
scanf("%d%d",&f[i],&g[i]);//读入
for (int i=1;i<=m;i++)
for (int j=t;j>=f[i];j--)
a[j]=max(a[j],a[j-f[i]]+g[i]);//公式
printf("%d",a[t]);//输出
return 0;
}