NC19158 失衡天平

题目链接

题目

题目描述

终于Alice走出了大魔王的陷阱,可是现在傻傻的她忘了带武器了,这可如何是好???这个时候,一个神秘老人走到她面前答应无偿给她武器,但老人有个条件,需要将所选武器分别放在天平的两端,若天平平衡则可以将天平上的所有武器拿走,还好这个天平锈迹斑斑,只要两端重量相差小于等于m就会保持平衡,Alice傻傻的认为越重的武器越好,求Alice最多能拿走的武器总重量。(不限操作次数)

输入描述

第一行2个整数 n, m;
第二行n个整数x,分别表示n件武器的重量。
1 <= n <= 100; 0 <= m <= 100; 1 <= x <= 100;

输出描述

一个整数,表示Alice最多能拿走的武器总重量。

示例1

输入

5 4
1 5 61 65 100

输出

132

说明

可以称两次,第1次:(1 ; 5),第二次(61 ; 65)。

示例2

输入

5 0
10 20 30 40 100

输出

200

说明

称一次,(10,20,30,40 ; 100)。

题解

知识点:背包dp。

01背包变种。设 \(dp[i][j]\) 为考虑了 \(i\) 个物品天平两遍差的绝对值为 \(j\) 的最大值。因为天平左右两边可以随时互换,我们只考虑绝对值即可。转移方程为:

\[dp[i][j] = \max(dp[i-1][j],dp[i-1][j+w[i]]+w[i],dp[i-1][|j-w[i]|]+w[i]) \]

注意边界,而且 \(j\) 的范围应该是 \([0,\sum w_i]\) ,而不是 \([0,m]\) ,因为可以放天平另一端平衡。

最后找到 \(dp[n][0\cdots m]\) 的最大值即可。

时间复杂度 \(O(n\sum w_i)\)

空间复杂度 \(O(n\sum w_i)\)

代码

#include <bits/stdc++.h>

using namespace std;

int dp[107][10007], w[107];

int main() {
    std::ios::sync_with_stdio(0), cin.tie(0), cout.tie(0);
    int n, m, sum = 0;
    cin >> n >> m;
    for (int i = 1;i <= n;i++) cin >> w[i], sum += w[i];
    memset(dp, -0x3f, sizeof(dp));///必须负无穷,不能填空气,因为可能导致所有物品都能放
    dp[0][0] = 0;
    for (int i = 1;i <= n;i++) {
        for (int j = 0;j <= sum;j++) { ///不能到m就结束,因为可能从后面传递
            dp[i][j] = dp[i - 1][j];
            if (j + w[i] <= sum) dp[i][j] = max(dp[i][j], dp[i - 1][j + w[i]] + w[i]);
            if (abs(j - w[i]) <= sum) dp[i][j] = max(dp[i][j], dp[i - 1][abs(j - w[i])] + w[i]);
        }
    }
    int ans = 0;
    for (int i = 0;i <= m;i++) ans = max(ans, dp[n][i]);
    cout << ans << '\n';
    return 0;
}
posted @ 2022-08-12 21:04  空白菌  阅读(26)  评论(0编辑  收藏  举报