你有一架天平和 N个砝码,这 N个砝码重量依次是 W1,W2,⋅⋅⋅,WN。
请你计算一共可以称出多少种不同的正整数重量?
注意砝码可以放在天平两边。
输入格式
输入的第一行包含一个整数 N。
第二行包含 N 个整数:W1,W2,W3,⋅⋅⋅,WN;
输出格式
输出一个整数代表答案。
数据范围
对于 50%50% 的评测用例,1≤N≤15
对于所有评测用例,1≤N≤100,N个砝码总重不超过 10^5。
输入样例:
3
1 4 6
输出样例:
10
注:不了解闫氏DP分析法的小伙伴可以去b站直接搜索,强推y总总结的该方法;
解析:闫氏DP分析法
状态表示(化零为整):
集合:dp[i][j]代表用前i个砝码凑出重量为j的所有方案
属性:该集合是否为空(是否没有方案表示该重量) 布尔类型
状态计算(化整为零):
核心:按照最后一个不同点划分集合
集合dp[i][j]: 每个砝码有三种摆放方法:不放 放在天平左边 放在天平右边
由题意可得:无论左边大于右边还是右边大于左边差值都算为正数 比如左5右2和左2右5都表示正整数3;
该集合内的任意子集不为空那么全集就不为空
运行代码:
初始化注意:M为砝码相加最大总重量;根据题意得 N个法码的总重不超过10的5次方,并且在j=sum时还有一个j+w[i]的状态 ,最后有一个砝码的重量最大可以为十万(此时只有一个砝码),因此M最大为二十万;
import java.util.Scanner;
//dp[i][j]表示使用前i个砝码凑出重量j的方案是否为空
//划分集合:最后一个不同点是砝码放左边,不放,放右边
public class famachengzhong {
static int N = 110;
static int M =200010 ;
static int n;
static int w[] = new int[N];
static boolean dp[][] = new boolean[N][M];
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
n = sc.nextInt();
int sum = 0;
for (int i = 1; i <= n; i++) {
w[i] = sc.nextInt();
sum += w[i];
}
dp[0][0] = true;
for (int i = 1; i <=n; i++) {
for (int j = 0; j <=sum; j++) {
//注意不管右边比左边大还是左边比右边大都属于正整数
if (dp[i - 1][j] || dp[i - 1][Math.abs(j - w[i])] || dp[i - 1][j + w[i]])
dp[i][j] = true;
}
}
int res = 0;
for (int i = 1; i <= sum; i++) {
if (dp[n][i])
res++;
}
System.out.println(res);
}
}