信息学奥赛一本通 1272:【例9.16】分组背包

【题目链接】

ybt 1272:【例9.16】分组背包

【题目考点】

1. 动态规划:分组背包

【解题思路】

分组背包问题,特点是:每组中的物品最多可以取一件

1. 状态定义

集合:放入背包的物品方案
限制:物品所在分组的区间,背包大小
属性:价值
条件:最大
统计量:价值
状态定义
dp[i][j]: 在前i组物品中选择物品放入大小为j的背包能获得的最大价值。

2. 状态转移方程

记第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]
  • 以上所有情况求最大值。
3. 复杂度分析

背包容量为V,物品总数量为N,分组数量为T。
分组背包一般解法:

  • 时间复杂度: O ( V N ) O(VN) O(VN)
  • 空间复杂度: O ( T V ) O(TV) O(TV)

滚动数组优化后:

  • 空间复杂度: O ( V ) O(V) O(V)

【题解代码】

解法1:分组背包 一般解法
#include<bits/stdc++.h>
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<int> 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;
}
解法2:分组背包 滚动数组优化
#include<bits/stdc++.h>
using 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<int> 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;
}
  • 3
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值