题目
你有一架天平和 N 个砝码,这 N 个砝码重量依次是 W1,W2,⋅⋅⋅,WN。
请你计算一共可以称出多少种不同的正整数重量?
注意砝码可以放在天平两边。
输入格式
输入的第一行包含一个整数 N。
第二行包含 N 个整数:W1,W2,W3,⋅⋅⋅,WN。
输出格式
输出一个整数代表答案。
数据范围
对于 50% 的评测用例,1≤N≤15。
对于所有评测用例,1≤N≤100,N 个砝码总重不超过 105。
思路
当时并没有做出来…看了点y总的思路然后自己做啦。
每个砝码有放+Wi、不放0、和放在另一边-Wi的选择,有限的选择问题——背包问题
背包问题:
- 1.状态表示:f(i,j):{集合:只从前N个砝码中选,且称出来总重量为j的可行性的集合;属性:Boolean}
- 2.状态转移:f(i,j):第i个{选+:f(i,j)=f(i-1,j-wi);选-:f(i,j)=f(i-1,j+wi);不选:f(i,j)=f(i-1,j)}.
- 每个f[i][j] = f[i][j] || 转移来的
光看思路比较简单,实际写代码还是会遇到一些bug
package blueBridgeCB2021First;
/**
* 砝码称重
* https://www.acwing.com/problem/content/3420/
* AC
* 问题:f[i][j] = f[i][j]||f[i-1][j-W[i]];这一段有问题,因为当Wi=j时,因为f[0][0]=false,导致f[i][j]=false,应该把
* f[0][0]=true,最后计数时再减掉
* 问题2:砝码排列后范围是[-total,total],需要加偏移量100000,[0,200000]
* 问题3:样例答案9出不来,原因是首先要放一个-1,即f[0][-W[0]]=true,这个忘掉了
*/
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
public class T3417 {
static int OFF = 100000;
static String[] s;
static int N;
static int[] W;
static boolean[][] f;
public static void main(String[] args) throws IOException {
BufferedReader in = new BufferedReader(new InputStreamReader(System.in));
s = in.readLine().split(" ");
N = Integer.valueOf(s[0]);
W = new int[N];
s = in.readLine().split(" ");
for (int i = 0; i < N; i++) {
W[i] = Integer.valueOf(s[i]);
}
f = new boolean[N][200001];
f[0][W[0]+OFF] = true;
f[0][0+OFF] = true;
f[0][-W[0]+OFF] = true;
for (int i = 1; i < N; i++) {
for (int j = 0; j < 200001; j++) {
f[i][j] = f[i][j]||f[i-1][j];
if(j+W[i]<200001)
f[i][j] = f[i][j]||f[i-1][j+W[i]];
if(j-W[i]>=0)
f[i][j] = f[i][j]||f[i-1][j-W[i]];
}
}
int count=-1;
for (int i = 100000; i <=200000; i++) {
if(f[N-1][i]) {
count++;
}
}
System.out.println(count);
}
}