1 条题解

  • 0
    @ 2026-10-31 17:58:18

    思路

    每个物品有三种去向,而且受三重容量约束,本质是三维 0/1 背包。

    约束:

    1. 随身背包体积之和 ≤V1\le V_1;
    2. 保险箱体积之和 ≤V2\le V_2;
    3. 两部分共用负重,∑w背包+∑w保险箱≤W\sum w_{\text{背包}}+\sum w_{\text{保险箱}}\le W。

    价值: 放入背包得 valval,放入保险箱得 0.8⋅val0.8\cdot val。为避免浮点误差,把价值统一乘以 1010:背包记 10val10val,保险箱记 8val8val,最后除以 1010 保留一位小数输出。

    状态: dp[i][j][k]dp[i][j][k] 表示处理完当前物品后,背包容量不超过 ii、保险箱容量不超过 jj、总重量不超过 kk 时的最大价值(价值已乘 1010)。

    转移: 对物品 (v,w,val)(v,w,val),三个维度都倒序枚举(保证每件物品最多用一次):

    • 不带走:保持原值;
    • 放入背包(需 i≥vi\ge v、k≥wk\ge w):
    $$dp[i][j][k]=\max\left(dp[i][j][k],\ dp[i-v][j][k-w]+10val\right)$$
    • 放入保险箱(需 j≥vj\ge v、k≥wk\ge w):
    $$dp[i][j][k]=\max\left(dp[i][j][k],\ dp[i][j-v][k-w]+8val\right)$$

    答案为 dp[V1][V2][W]/10dp[V_1][V_2][W]/10,保留一位小数。

    实现: 边读入边转移,不保存全部物品;数组按 (V1+1)×(V2+1)×(W+1)(V_1+1)\times(V_2+1)\times(W+1) 精确开维以节省内存。

    复杂度: 时间 O(nV1V2W)O(nV_1V_2W)(题面保证 nV1V2W≤5×107nV_1V_2W\le5\times10^7),空间 O(V1V2W)O(V_1V_2W)。

    代码

    #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
    上传者