ybt 1272:【例9.16】分组背包
【题目考点】 1. 动态规划:分组背包 【解题思路】分组背包问题,特点是:每组中的物品最多可以取一件
1. 状态定义集合:放入背包的物品方案
限制:物品所在分组的区间,背包大小
属性:价值
条件:最大
统计量:价值
状态定义:
dp[i][j]: 在前i组物品中选择物品放入大小为j的背包能获得的最大价值。
记第i组物品有m个,这m个物品的编号为i1,i2,…,im。
第i物品的重量是w[i],价值是c[i]。
集合:在前i组物品中选择物品放入大小为j的背包的所有方案
分割集合:第i组物品如何放入背包
- 如果不选择第i组物品,那么在剩余i-1组中选择物品放入大小为j的背包。dp[i][j] = dp[i-1][j]
- 如果选择第i组物品中的第1个,该物品下标为i1。那么需要在剩余i-1组中选择物品放入大小为j-w[i1]的背包。dp[i][j] = dp[i-1][j-w[i1]]+c[i1]
- 如果选择第i组物品中的第2个,该物品下标为i2。那么需要在剩余i-1组中选择物品放入大小为j-w[i2]的背包。dp[i][j] = dp[i-1][j-w[i2]]+c[i2]
… - 如果选择第i组物品中的第m个,该物品下标为im。那么需要在剩余i-1组中选择物品放入大小为j-w[im]的背包。dp[i][j] = dp[i-1][j-w[im]]+c[im]
- 一般地,如果选择第i组物品中的第k个,该物品下标为x。那么需要在剩余i-1组中选择物品放入大小为j-w[x]的背包。dp[i][j] = dp[i-1][j-w[x]]+c[x]。遍历第i组物品,求选择该组中每个物品后能得到的最大价值dp[i][j]。
- 以上所有情况求最大值。
背包容量为V,物品总数量为N,分组数量为T。
分组背包一般解法:
- 时间复杂度: O ( V N ) O(VN) O(VN)
- 空间复杂度: O ( T V ) O(TV) O(TV)
滚动数组优化后:
- 空间复杂度: O ( V ) O(V) O(V)
#include解法2:分组背包 滚动数组优化using namespace std; #define V 205 #define N 35 #define T 15 int dp[N][V], w[N], c[N]; //dp[i][j]:在前i组物品中选择物品放入大小为j的背包能获得的最大价值。 vector g[T];//g[i]:存储第i组物品的编号 int main() { int v, n, t, p; cin >> v >> n >> t; for(int i = 1; i <= n; ++i) { cin >> w[i] >> c[i] >> p; g[p].push_back(i);//第p组添加i } for(int i = 1; i <= t; ++i)//遍历各组 { for(int j = 0; j <= v; ++j) { dp[i][j] = dp[i-1][j]; for(int k = 0; k < g[i].size(); ++k) { int x = g[i][k]; if(w[x] <= j) dp[i][j] = max(dp[i][j], dp[i-1][j-w[x]]+c[x]); } } } cout << dp[t][v]; return 0; }
#includeusing namespace std; #define V 205 #define N 35 #define T 15 int dp[V], w[N], c[N]; //dp[i][j]:(第1维被优化掉)在前i组物品中选择物品放入大小为j的背包能获得的最大价值。 vector g[T];//g[i]:存储第i组物品的编号 int main() { int v, n, t, p; cin >> v >> n >> t; for(int i = 1; i <= n; ++i) { cin >> w[i] >> c[i] >> p; g[p].push_back(i);//第p组添加i } for(int i = 1; i <= t; ++i)//遍历各组 { for(int j = v; j >= 0; --j) { for(int k = 0; k < g[i].size(); ++k) { int x = g[i][k]; if(j >= w[x]) dp[j] = max(dp[j], dp[j-w[x]]+c[x]); } } } cout << dp[v]; return 0; }



