1 条题解
-
0
思路
每个物品有三种去向,而且受三重容量约束,本质是三维 0/1 背包。
约束:
- 随身背包体积之和 ;
- 保险箱体积之和 ;
- 两部分共用负重,。
价值: 放入背包得 ,放入保险箱得 。为避免浮点误差,把价值统一乘以 :背包记 ,保险箱记 ,最后除以 保留一位小数输出。
状态: 表示处理完当前物品后,背包容量不超过 、保险箱容量不超过 、总重量不超过 时的最大价值(价值已乘 )。
转移: 对物品 ,三个维度都倒序枚举(保证每件物品最多用一次):
- 不带走:保持原值;
- 放入背包(需 、):
- 放入保险箱(需 、):
答案为 ,保留一位小数。
实现: 边读入边转移,不保存全部物品;数组按 精确开维以节省内存。
复杂度: 时间 (题面保证 ),空间 。
代码
#include<bits/stdc++.h> #define int long long #define el cout << '\n' using namespace std; void go(){ int n, v1, v2, W; cin >> n >> v1 >> v2 >> W; // 物品数、背包容量、保险箱容量、负重上限 // dp[i][j][k]:背包容量不超过 i、保险箱容量不超过 j、总重量不超过 k 的最大价值(价值乘 10) vector<vector<vector<int>>> dp( v1 + 1, vector<vector<int>>(v2 + 1, vector<int>(W + 1, 0))); // 边读入边转移,避免存储全部物品 for(int i = 0; i < n; i++){ int v, w, val; cin >> v >> w >> val; // 倒序枚举,保证每个物品最多使用一次 for(int a1 = v1; a1 >= 0; a1--){ for(int b1 = v2; b1 >= 0; b1--){ for(int a2 = W; a2 >= w; a2--){ // 放入背包:占用背包容量和重量,价值乘以 10 if(a1 >= v){ dp[a1][b1][a2] = max(dp[a1][b1][a2], dp[a1-v][b1][a2-w] + val * 10); } // 放入保险箱:占用保险箱容量和重量,价值只有 0.8 倍,乘以 10 后即 8 if(b1 >= v){ dp[a1][b1][a2] = max(dp[a1][b1][a2], dp[a1][b1-v][a2-w] + val * 8); } } } } } // 价值已放大 10 倍,除回来并保留一位小数 cout << fixed << setprecision(1) << dp[v1][v2][W] / 10.0; el; } signed main() { ios::sync_with_stdio(false); cin.tie(nullptr); cout.tie(nullptr); int _ = 1; // 本题只有单组数据 while(_--){ go(); } return 0; }
- 1
信息
- ID
- 24
- 时间
- 1000ms
- 内存
- 256MiB
- 难度
- 5
- 标签
- 递交数
- 0
- 已通过
- 0
- 上传者