1 条题解
-
0
#include <bits/stdc++.h> using namespace std; int n,m; // [1] n-待选物品总数;m-总拨款金额(元) struct stu{ int v,p,num; // [2] v-虚拟物品的总价格;p-虚拟物品的总价值;num-该虚拟物品对应的原物品数量 }arr[1001000]; // [3] arr数组-存储二进制拆分后的所有“虚拟物品” int dp[1001000]={}; // [4] dp数组-动态规划状态,dp[j]表示用j元钱能买到的最大价值 int main() { // 问题分析:多重背包问题,每种物品有价格、价值和购买数量限制,求m元能买的最大价值 // 解题步骤:用二进制拆分将多重背包转化为01背包(把原物品的数量拆成1,2,4,...等份的虚拟物品),再用01背包求解 cin>>n>>m; // [5] 读取待选物品数n和总拨款m int x=1,a,b,c; // [6] x-虚拟物品的计数指针;a-原物品的单价;b-原物品的单位价值;c-原物品的最大购买数量 // 遍历每种物品,进行二进制拆分 for(int i=1;i<=n;i++){ cin>>a>>b>>c; // [7] 读取当前物品的单价a、单位价值b、最大购买数量c // 二进制拆分:把c件物品拆成1,2,4,...等份,每份作为一个虚拟物品 int j=1; while(j<=c){ arr[x].v = a*j; // [8] 虚拟物品的总价格 = 单价 * 份数j arr[x].p = b*j; // [9] 虚拟物品的总价值 = 单位价值 * 份数j arr[x++].num = j; // [10] 记录该虚拟物品对应的原物品数量,x指针后移 c -= j; // [11] 剩余数量减去已拆分的份数j j *= 2; // [12] 份数翻倍,继续拆分 } if(c){ // [13] 如果还有剩余数量(不足2的幂次),单独作为一个虚拟物品 arr[x].v = a*c; arr[x].p = b*c; arr[x++].num = c; } } // 01背包求解:遍历所有虚拟物品,逆序更新dp数组 dp[0]=0; // [14] 初始化:0元钱能买0价值 for(int i=1;i<x;i++){ // [15] 遍历所有二进制拆分后的虚拟物品 for(int j=m;j>=arr[i].v;j--){ // [16] 逆序遍历资金,避免重复选择同一虚拟物品 // 状态转移:不选当前物品时dp[j]不变;选当前物品时,dp[j-arr[i].v] + arr[i].p dp[j] = max(dp[j], dp[j-arr[i].v] + arr[i].p); // [17] 取两种情况的最大值 } } cout<<dp[m]; // [18] 输出m元能买到的最大价值 return 0; }
- 1
信息
- ID
- 1337
- 时间
- 1000ms
- 内存
- 256MiB
- 难度
- 10
- 标签
- 递交数
- 1
- 已通过
- 1
- 上传者