试题 G: 砝码称重【省赛】【A组】java

试题 G: 砝码称重【省赛】【A组】java

写的时候意外遇到了这题,当时我想了20多分钟,感觉暴力法很难做(暴力法我都写不出来呜呜),我好菜,感觉要用动态规划(但我也刚入门学dp)然后参考了其他博主的博客,用dp来尝试写了一下

参控 砝码称重

【问题描述】
你有一架天平和 N 个砝码,这 N 个砝码重量依次是 W1, W2, · · · , WN。 请你计算一共可以称出多少种不同的重量? 注意砝码可以放在天平两边。
【输入格式】
输入的第一行包含一个整数 N。
第二行包含 N 个整数:W1, W2, W3, · · · , WN。
【输出格式】
输出一个整数代表答案。
【样例输入】
3
1 4 6
【样例输出】
10
【样例说明】
能称出的 10 种重量是:1、2、3、4、5、6、7、9、10、11。
1 = 1;
2 = 6 − 4 (天平一边放 6,另一边放 4);
3 = 4 − 1;
4 = 4;
5 = 6 − 1;
6 = 6;
7 = 1 + 6;
9 = 4 + 6 − 1;
10 = 4 + 6;
11 = 1 + 4 + 6。

注意

  1. 暴力法我感觉很复杂,而且不好写(没写出来 )(欢迎大家提供好的暴力思路)
  2. 采用dp(动态规划),简单很多

分析

1.n=3,砝码重量为1,4,6

2.取1,可能为1,取1,4,可能为1+4=5,1-4=3,1,4,取1,4,6可能为1+6,1-6,3+6,3-6,5+6,5-6,6+4,6-4,6,以及之前的状态1,4,3,5,然后去重;

3.动态规划数组dp[i][j],i代表取的第几个数j代表所有砝码重量的可能值因为砝码总重<10万,所以可能性<10万)所以dp[i][10万],weight[]代表输入的重量。

4 dp[1][weight[0]]=1代表初始状态,dp[1][j]相当于取1,j相当于重量,dp[2][j]代表取2,但是要把dp[1][j]的值重新赋值到dp[2][j] , 因为要对dp[2]【weight【i】+或者-之前存储的重量】然后再dp[2][weight【i】+或者-之前存储的重量]=1 . 再dp[3]=dp[2];重复操作…

代码

import java.util.Scanner;

public class 砝码称重 {

	public static void main(String[] args) {
		// TODO Auto-generated method stub
		Scanner input = new Scanner(System.in);
		int n = input.nextInt();// 要测试的个数
		int[] weight = new int[n];// 存放砝码重量的数组
		int sum = 0;// 砝码重量和,砝码重量的可能性一定小于100000(10万)
		int count = 0;// 可能种类
		for (int i = 0; i < n; i++) {// 输入砝码重量
			weight[i] = input.nextInt();
			sum += sum + weight[i];
		}
		// n存放状态例如放入几个,sum存入做所有可能的值。
		int[][] dp = new int[n + 1][sum + 1];
		// dp---------------------动态规划代码
		dp[1][weight[0]] = 1;// 初始化;
		// 进行之后状态,依次取砝码
		for (int i = 2; i <= n; i++) {
			for(int j=1;j<=sum;j++) {
				dp[i][j]=dp[i-1][j];//继承上一个重量的种类
			}
			dp[i][weight[i-1]]=1;//自己也算一种重量
			for (int j = 1; j <= sum; j++) {
				if (dp[i - 1][j] == 1) {//上一个重量状态的种类
					dp[i][weight[i - 1] + j] = 1;//加法
					dp[i][Math.abs(weight[i - 1] - j)] = 1;//减
				}
			}			
		}
		for (int j = 1; j <= sum; j++) {//遍历所有重量
			if (dp[n][j] == 1) {
				count++;
			}
		}
		// dp----------------------动态规划代码
		System.out.println(count);
	}
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

山海上的风

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值