1 条题解
-
0
#include <bits/stdc++.h> using namespace std; int n,m,t; // [1] t-测试用例组数;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背包(把c袋粮食拆成1,2,4,...等份的虚拟物品),再用01背包求解 cin>>t; // [5] 读取测试用例组数 while(t--){ // [6] 处理每组测试用例 cin>>m>>n; // [7] 读取当前组的资金m和粮食种类数n memset(dp,0,sizeof(dp)); // [8] 初始化dp数组为0(每组测试用例独立,需重置) int x=1,a,b,c; // [9] x-虚拟物品的计数指针;a-单袋价格;b-单袋重量;c-该粮食的总袋数 // 遍历每种粮食,进行二进制拆分 for(int i=1;i<=n;i++){ cin>>a>>b>>c; // [10] 读取当前粮食的单袋价格a、单袋重量b、总袋数c // 二进制拆分:把c袋拆成1,2,4,...等份,每份作为一个虚拟物品 int j=1; while(j<=c){ arr[x].v = a*j; // [11] 虚拟物品的总价格 = 单袋价格 * 份数j arr[x].p = b*j; // [12] 虚拟物品的总重量 = 单袋重量 * 份数j arr[x++].num = j; // [13] 记录该虚拟物品对应的袋数,x指针后移 c -= j; // [14] 剩余袋数减去已拆分的份数j j *= 2; // [15] 份数翻倍,继续拆分 } if(c){ // [16] 如果还有剩余袋数(不足2的幂次),单独作为一个虚拟物品 arr[x].v = a*c; arr[x].p = b*c; arr[x++].num = c; } } // 01背包求解:遍历所有虚拟物品,逆序更新dp数组 dp[0]=0; // [17] 初始化:0元钱能买0重量 for(int i=1;i<x;i++){ // [18] 遍历所有二进制拆分后的虚拟物品 for(int j=m;j>=arr[i].v;j--){ // [19] 逆序遍历资金,避免重复选择同一虚拟物品 // 状态转移:不选当前物品时dp[j]不变;选当前物品时,dp[j-arr[i].v] + arr[i].p dp[j] = max(dp[j], dp[j-arr[i].v] + arr[i].p); // [20] 取两种情况的最大值 } } cout<<dp[m]<<endl; // [21] 输出当前组m元能买到的最大重量 } return 0; }
- 1
信息
- ID
- 1338
- 时间
- 1000ms
- 内存
- 256MiB
- 难度
- 10
- 标签
- 递交数
- 1
- 已通过
- 1
- 上传者