有 N 件物品和一个容量是 V 的背包。每件物品只能使用一次。
第 i 件物品的体积是 v,价值是 w
求解将哪些物品装入背包,可使这些物品的总体积不超过背包容量,且总价值最大。
输出最大价值。输入格式
第一行两个整数, N,V ,用空格隔开,分别表示物品数量和背包容积。
接下来有 N 行,每行两个整数 vi, wi,用空格隔开,分别表示第 i 件物品的体积和价值。
输出格式
输出一个整数,表示最大价值。
数据范围
0<N,V≤10000<N,V≤1000
0<vi,wi≤1000输入样例
4 5
1 2
2 4
3 4
4 5输出样例:
8
01背包问题----每个物体最多只能用一次
二维
1.状态表达式----------dp(i,j)
i代表前i个物体,j代表目前的总容量 dp(i,j)表示前i个物体在总容量为j里价值最高的值
即最后答案输出dp(N,V);
2.条件
只在前i个物品中选择
总体积<=j
3.属性----max
题目要求得到价值最大值
4.状态计算
一共分为两种情况
不放物品i 即 dp(i,j)=dp(i-1,j);
放入物品i dp(i,j)=dp(i-1,j-v[i])+w[i];
(i-1,j-v[i]) 在容量为j-v[i]里面 不放入i-1 的价值max +w[i]
如果v[i]>j 当前背包容量装不进第i个物品,则将无法放入物品i ,dp(i,j)=dp(i-1,j);
if(v[i] > j)
dp[i][j] = dp[i - 1][j];
else
dp[i][j] = max(dp[i - 1][j], dp[i - 1][j - v[i]] + w[i]);
#include <iostream>
#include<algorithm>
using namespace std;
const int N = 1010;
int v[N];
int w[N];
int dp[N][N];
int main()
{
int n, m;
cin >> n >> m;
for (int i = 1; i <= n; i++)
cin >> v[i] >> w[i];
for (int i = 1; i <= n; i++)
for (int j = 1; j <= m; j++)
{
if(v[i] > j)
dp[i][j] = dp[i - 1][j];
else
dp[i][j] = max(dp[i - 1][j], dp[i - 1][j - v[i]] + w[i]);
}
cout << dp[n][m];
}
一维
由于每次更新数组我们只需要利用到上一行代码,那么我们可以利用滚动数组来更新。
即在没有更新f[j]的时候 此f[j]为上一行的f[j]
1 状态f[j]定义:N 件物品,背包容量j下的最优解。
2 .状态计算
一共分为两种情况
不放物品i 即 dp(j)=dp(j);
放入物品i dp(j)=dp[j - v[i]] + w[i]
3 注意枚举背包容量j必须从m开始依次减小。
因为我们在运算的dp[j - v[i]]的时候我们是需要运用的上一行的dp[j - v[i]] 如果枚举j从小到大我们将会污染dp[j - v[i]]
4 j从m开始依次减小
直到v[i]结束
因为当j小于v[i]的时候是无法放入物品的,可以根据滚动数组的特性即在没有更新f[j]的时候 此f[j]为上一行的f[j]
#include <iostream>
#include<algorithm>
using namespace std;
int n, m;
const int N = 10100;
int v[N], w[N];
int dp[N];
int main()
{
cin >> n >> m;
for (int i = 1; i <= n; i++)
{
cin >>v[i] >> w[i];
for (int j = m; j >= v[i]; j--)
{
dp[j] = max(dp[j], dp[j - v[i]] + w[i]);
}
}
cout << dp[m];
}