动态规划(DP)(3)——背包问题(2)

分组背包

  • 有 n 种物品要放到一个袋子里,袋子的总容量为 m。第 i 个物品属于第 ai 组,每组物品我们只能从中选择一个。第 i 种物品的体积为 vi,把它放进袋子里会获得 wi 的收益。问如何选择物品,使得在物品的总体积不超过 m 的情况下,获得最大的收益?请求出最大收益。
    • 输入格式:
      第一行两个整数 n,m。接下来 n行,每行三个整数 ai,vi,wi。
    • 输出格式:
      一个整数,表示答案。
    • 数据规模;
      对于所有数据,保证 1≤n,m,ai,vi,wi≤1000。
  • 核心思想是利用vector将同组的数据存放在一起。需要注意在后面循环的时候,外层循环的 i 指的是组数而不是01背包问题里面的物品序号。
#include<bits/stdc++.h>

using namespace std;

int n, m, f[1001], v[1001], w[1001], a[1001];
vector<int>c[1001];

int main(){
    scanf("%d%d", &n, &m);
    for(int i = 1; i <= n; i++){
        scanf("%d%d%d", &a[i], &v[i], &w[i]);
        c[a[i]].push_back(i);;
    }
    for(int i = 1; i <= 1000; i++)
        for(int j = m; j  ; j--)
            for(auto k: c[i])
                if(v[k] <= j)
                    f[j] = max(f[j], f[j - v[k]]+ w[k]);
    printf("%d", f[m]);
}

二维背包

  • 有 n 种物品要放到一个袋子里,袋子的总容量为 m,我们一共有 k 点体力值。第 i 种物品的体积为 vi,把它放进袋子里会获得 wi 的收益,并且消耗我们 ti 点体力值,每种物品只能取一次。问如何选择物品,使得在物品的总体积不超过 m 并且花费总体力不超过 k 的情况下,获得最大的收益?请求出最大收益。
    • 输入格式:
      第一行三个整数 n,m,k。接下来 n行,每行三个整数 vi,wi,ti。
    • 输出格式:
      一个整数,表示答案。
    • 数据规模;
      对于所有数据,保证 1≤n,m,ai,vi,wi≤100。
#include<bits/stdc++.h>

using namespace std;

int n, m, k, f[101][101], v[101], w[101], t[101];

int main(){
    scanf("%d%d%d", &n, &m, &k);
    for(int i = 1; i <= n; i++)
        scanf("%d%d%d", &v[i], &w[i], &t[i]);
       
    for(int i = 1; i <= n; i++)
        for(int j = m; j >= v[i] ; j--)
            for(int x = k; x >= t[i]; x--)
                    f[j][x] = max(f[j][x], f[j - v[i]][ x - t[i]]+ w[i]);
    printf("%d", f[m][k]);
}

多重背包3*

  • 有 n 种物品要放到一个袋子里,袋子的总容量为 m,第 i 种物品的体积为 vi,把它放进袋子里会获得 wi 的收益,一共有 li 个。问如何选择物品,使得在物品的总体积不超过 m 的情况下,获得最大的收益?请求出最大收益。
    • 输入格式
      第一行两个整数 n,m。
      接下来 n行,每行两个整数 vi,wi。
    • 输出格式
      一个整数,表示答案
    • 数据规模
      对于所有数据,保证 1≤n,m,vi,wi, li≤ 10000
  • 先将数据按照mod vi 分类后再使用单调队列进行排序。
#include<bits/stdc++.h>

using namespace std;

int n, m, v, l, w, p, x, c[10001][2], f[10001];

int main(){
    scanf("%d%d", &n, &m);
    for(int i = 1; i <= n; i++){
        scanf("%d%d%d", &v, &w, &l);
        for(int j = 0; j < v; j++){
            int h = 1, t = 0;
            for(p = j, x = 1; p <= m; p += v, ++x){
                int e = f[p] - x * w, r = x + l;
                for(; t >= h && e >= c[t][1]; --t);
                c[++t][0] = r; c[t][1] = e;
                f[p] = c[h][1] + x * w;
                for(; t >= h && c[h][0] == x; ++h);
            }
        }
    }
    printf("%d", f[m]);
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值