砝码称重 JAVA(闫氏DP详解)

你有一架天平和 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);
	}
}

  • 5
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值