失衡天平
https://ac.nowcoder.com/acm/contest/24213/1021
题目描述
终于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)。
提示
解析
为了便于操作,造数据如下:
4 2
1 2 4 5
12
DP 信息:
- 原问题:将一堆物品分成两堆,他们的天平差不能超过 m,求最大重量
- 子问题:求前 i 个物品,满足天平差 j 下的最大值
- DP 定义: d p [ i ] [ j ] dp[i][j] dp[i][j] 将前 i 个物品进行天平的摆放,天平差为 j 时的最大重量
- DP 方程:有三种情况
- 不放: d p [ i ] [ j ] = m a x ( d p [ i ] [ j ] , d p [ i − 1 ] [ j ] ) dp[i][j] = max(dp[i][j], dp[i-1][j]) dp[i][j]=max(dp[i][j],dp[i−1][j])
- 放右边: d p [ i ] [ j + W [ i ] ] = m a x ( d p [ i ] [ j + W [ i ] ] , d p [ i − 1 ] [ j ] + W [ i ] ) dp[i][j+W[i]] = max(dp[i][j+W[i]], dp[i-1][j] + W[i]) dp[i][j+W[i]]=max(dp[i][j+W[i]],dp[i−1][j]+W[i])
- 放左边: d p [ i ] [ j − W [ i ] ] = m a x ( d p [ i ] [ j − W [ i ] ] , d p [ i − 1 ] [ j ] + W [ i ] ) dp[i][j-W[i]] = max(dp[i][j-W[i]], dp[i-1][j] + W[i]) dp[i][j−W[i]]=max(dp[i][j−W[i]],dp[i−1][j]+W[i])
解释DP的第二维,天平差为 j 是的最大重量:
dp[2][1] = 3 // 放入前2个物品,天平差为1时,最大值为3
那么如何体现这句话呢?
先将前2个物品进行天平摆放:
(1)+(2) // 天平差为1,最大值为3
dp[2][2] = 2 // 放入前2个物品,天平差为2时,最大值为2
(0)+(2) // 天平差为2,最大值为2
dp[3][1] = 7 // 放入前3个物品,天平差为1时,最大值为7
(1+2)+(4)=7 // 天平差为1,最大值为7
dp[3][2] = dp[2][2] + 4 = 6
dp[3][2] = max(dp[3][2], dp[2][2]);
dp[3][2+4] = max(dp[3][2+4], dp[2][2+4] + W[3]);
dp[3][abs(2-4)] = max(dp[3][2], dp[2][2] + W[3]); // 2+4
// 前面dp[2][2]已经把前2个物品在天平差为2时的最大值计算好了
// 我们现在只是新加一个物品,因此在此基础上加上当前的物品重量即可。
以 d p [ 3 ] [ 1 ] = 7 dp[3][1]=7 dp[3][1]=7 为例,解释如何来的:
i = 3, j = 3, W[3] = 4
不放:dp[3][3] = max(dp[3][3], dp[2][3]);
放右边:dp[3][7] = max(dp[3][7], dp[2][7] + W[3]);
放左边:dp[3][1] = max(dp[3][1], dp[2][1] + W[3]); // 3(原本是3), 3+4
AC Code
import java.util.*;
public class Main {
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
int n = sc.nextInt(), m = sc.nextInt();
int[] W = new int[10005];
int[][] dp = new int[105][10005];
int sum = 0;
for(int i = 1; i <= n; i++) {
W[i] = sc.nextInt();
sum += W[i];
}
for(int i = 0; i <= n; i++) Arrays.fill(dp[i], -0x8f);
dp[0][0] = 0;
for(int i = 1; i <= n; i++) {
for(int j = 0; j <= sum; j++) {
dp[i][j] = Math.max(dp[i][j], dp[i-1][j]);
if(j + W[i] <= sum) dp[i][j+W[i]] = Math.max(dp[i][j+W[i]], dp[i-1][j] + W[i]);
dp[i][Math.abs(j-W[i])] = Math.max(dp[i][Math.abs(j-W[i])], dp[i-1][j] + W[i]);
}
}
int ans = 0;
for(int i = 0; i <= m; i++) {
ans = Math.max(ans, dp[n][i]);
}
System.out.println(ans);
}
}