【题解】01背包
【题目描述】
一个旅行者有一个最多能装 M 公斤的背包,现在有 n 件物品,它们的重量分别是W1,W2,...,Wn,它们的价值分别为C1,C2,...,Cn,求旅行者能获得最大总价值。
【输入描述】
第一行:两个整数,M(背包容量,M<=200)和N(物品数量,N<=30);
第2..N+1行:每行二个整数Wi,Ci,表示每个物品的重量和价值。
【输出描述】
仅一行,一个数,表示最大总价值。
【样例输入】
10 4 2 1 3 3 4 5 7 9
【样例输出】
12
【题目分析】
1. 状态定义
集合:将n件物品放入空间为M的背包的方案
限制:物品范围,背包空间
属性:价值
条件:最大
统计量:价值
状态定义:dp[i][j]表示将前i件物品放入大小为j的背包能获得的最大价值
2. 状态转移方程
记w[i]为第i个物品的重量,c[i]为第i个物品的价值。
分割集合:以第i物品是否放入背包分割集合
子集1:如果不将第i物品放入背包,那么将前i件物品放入大小为j的背包能获得的最大价值,即为将前i-1件物品放入大小为j的背包的最大价值,即dp[i][j] = dp[i-1][j]
子集2:如果确定将第i物品放入背包,此时背包剩下空间为j-w[i]。那么将前i件物品放入大小为j的背包能获得的最大价值,即为第i物品的价值c[i]加上将前i-1件物品放入空间为j-w[i]的背包能获得的最大价值,
即dp[i][j] = dp[i-1][j-w[i]]+c[i]
以上两种情况求最大值。
【参考答案】:二维数组
#include<bits/stdc++.h> using namespace std; #define N 35 #define M 250 int dp[N][M], w[N], c[N];//dp[i][j]:在前i个物品中选择物品放入大小为j的背包能获得的最大价值 int main() { int m, n; cin >> m >> n; for(int i = 1; i <= n; ++i) cin >> w[i] >> c[i]; for(int i = 1; i <= n; ++i) for(int j = 0; j <= m; ++j) { if(j >= w[i]) dp[i][j] = max(dp[i-1][j], dp[i-1][j-w[i]]+c[i]); else dp[i][j] = dp[i-1][j]; } cout << dp[n][m]; return 0; }
【参考答案】:一维数组
#include<bits/stdc++.h> using namespace std; #define N 35 #define M 250 int dp[M], w[N], c[N];//dp[i][j]:在前i个物品中选择物品放入大小为j的背包能获得的最大价值 int main() { int m, n; cin >> m >> n; for(int i = 1; i <= n; ++i) cin >> w[i] >> c[i]; for(int i = 1; i <= n; ++i) for(int j = m; j >= w[i]; --j) dp[j] = max(dp[j], dp[j-w[i]]+c[i]); cout << dp[m]; return 0; }
(adsbygoogle = window.adsbygoogle || []).push({});