有 N种物品和一个容量是 V 的背包,每种物品都有无限件可用。
第 ii种物品的体积是 vi,价值是 wi
求解将哪些物品装入背包,可使这些物品的总体积不超过背包容量,且总价值最大。
输出最大价值。
输入格式
第一行两个整数,N,V,用空格隔开,分别表示物品种数和背包容积。
接下来有 N行,每行两个整数 vi,wi,用空格隔开,分别表示第 i 种物品的体积和价值。
输出格式
输出一个整数,表示最大价值。
数据范围
0<N,V≤10000<N,V≤1000
0<vi,wi≤10000<vi,wi≤1000
输入样例
4 5
1 2
2 4
3 4
4 5
输出样例:
10
完全背包问题 可以重复使用
三重循环
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]
第二种情况 放入k个物品i dp[i][j]= dp[i-1][j-k*v[i]]+k*w[i]
其中k=0的时候 dp[i][j]= dp[i-1][j]就是第一种可能合并
k需要满足----k * v[i] <= j
枚举k算出其中最大值就是dp[i][j]的值
dp[i][j] = max(dp[i][j], dp[i - 1][j - k * v[i]] + k * 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++)
{
for (int k = 0; k * v[i] <= j; k++)
{
dp[i][j] = max(dp[i][j], dp[i - 1][j - k * v[i]] + k * w[i]);
}
}
}
cout << dp[n][m];
}
两重循环
三重循环所需要时间太多了我们简化一下状态转移方程
dp[i,j]=Max( dp[i-1,j] , dp[i-1,j-v]+w, dp[i-1,j-2v]+2w, dp[i-1,j-3v]+3w,...)
dp[i,j-v]Max( dp[i-1,j-v], dp[i-1,j-2v]+w, dp[i-1,j-3v)+2w…)
黄色部分明显就是dp[i,j-v]+w;
dp[i][j]=Max(dp[i-1][j],dp[i][j-v]+w)
#include<iostream>
using namespace std;
const int N = 1010;
int dp[N][N];
int v[N], w[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++)
{
dp[i][j] = dp[i - 1][j];
if (v[i] <= j)
dp[i][j] = max(dp[i][j], dp[i][j - v[i]] + w[i]);
}
cout << dp[n][m] << endl;
}
一维数组
(17条消息) 01背包问题(二维-->一维)_小花猴的博客-CSDN博客
01背包为了防止污染我们需要从后枚举(具体原因看以上链接),但完全背包恰巧是需要那种污染的,所以不需要从后枚举
由于每次更新数组我们只需要利用到上一行代码,那么我们可以利用滚动数组来更新。
即在没有更新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必须从v[i]开始
因为当j小于v[i]的时候是无法放入物品的,可以根据滚动数组的特性即在没有更新f[j]的时候 此f[j]为上一行的f[j] 即只能第一种情况:不放物品i 即 dp(j)=dp(j);
之后我们是可以多次放入物体i的,所以不能比较上一行(即不放物体i而是比较有可能放入物体idp[j - v[i]] 。
#include <iostream> #include<cstdio> #include<string> #include<cstring> #include<algorithm> using namespace std; const int N = 1010; int dp[N]; int v[N], w[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 = v[i]; j <= m; j++) { dp[j] = max(dp[j], dp[j - v[i]] + w[i]); } cout << dp[m] << endl; }