(算法提高课)-多重背包问题1

1019. 庆功会

为了庆贺班级在校运动会上取得全校第一名成绩,班主任决定开一场庆功会,为此拨款购买奖品犒劳运动员。
期望拨款金额能购买最大价值的奖品,可以补充他们的精力和体力。
输入格式
第一行二个数n,m,其中n代表希望购买的奖品的种数,m表示拨款金额。
接下来n行,每行3个数,v、w、s,分别表示第I种奖品的价格、价值(价格与价值是不同的概念)和能购买的最大数量(买0件到s件均可)。
输出格式
一行:一个数,表示此次购买能获得的最大的价值(注意!不是价格)。
数据范围
n≤500,m≤6000,
v≤100,w≤1000,s≤10
输入样例:
5 1000
80 20 4
40 50 9
30 50 7
40 30 6
20 20 1
输出样例:
1040

#include<bits/stdc++.h>
using namespace std;
const int N = 6010;

int f[N];

int main()
{
    int n,m; cin>>n>>m;
    for(int i = 0;i < n;i ++){
        int v,w,s;
        cin>>v>>w>>s;
        for(int j = m;j >= 0;j --){
            for(int k = 0;k <= s && k * v <= j;k ++){
                f[j] = max(f[j], f[j - k * v] + k * w);
            }
        }
    }
    cout<<f[m];
    return 0;
}


/* 朴素版本如下,注意自己写朴素版本的时候有写错!!!
注意状态转移那里并不是
f[i][j] = max(f[i - 1][j], f[i - 1][j - k * v] + k * w)
f[i][j] = max(f[i][j], 其他) 的目的是为了在出现比当前大的值才进行更新,出现的场景是在同样背包总重时,当前第I个物体放入件数不同,可能产生的价值不同(并不是同一个点只有一次更新机会所以不用比较再更新!!!理想情况下同一个点会被更新s次!!)而且当你走循环是从k = 0开始的时候,就考虑了当前物品完全不放入的情况

#include<bits/stdc++.h>
using namespace std;
const int N = 505, M = 6005;

int s[N], v[N], w[N];
int f[N][M];   //用来记录只放入前N种物品可以产生的最大价值

int main()
{
    int n, m;
    cin>>n>>m;
    
    for(int i = 1;i <= n;i ++){
        cin>>v[i]>>w[i]>>s[i];
    }

    for(int i = 1;i <= n;i ++){
        for(int j = 0;j <= m;j ++){
            for(int k = 0;k <= s[i] && k * v[i] <= j;k ++){
                //第I件物品放K件
                f[i][j] = max(f[i][j], f[i - 1][j - k * v[i]] + k * w[i]);
            }
            
        }
    }

    cout<<f[n][m];
    return 0;
}

学会比较各类背包问题,一个是内层循环的顺序不同,一个是条件不同,这里和买书问题又很像,不同的是这里不是恰好选满问题,而是价值最大问题

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值