历届真题 砝码称重 Java版 DP

230 阅读2分钟

题目

题目描述

你有一架天平和N 个砝码,这N 个砝码重量依次是W1, W2, … , WN。 请你计算一共可以称出多少种不同的重量? 注意砝码可以放在天平两边。

输入格式

输入的第一行包含一个整数N。

第二行包含N 个整数:W1, W2, W3, … , WN。

对于50% 的评测用例,1 ≤ N ≤ 15。

对于所有评测用例,1 ≤ N ≤ 100,N 个砝码总重不超过100000。

输出格式

输出一个整数代表答案。

输入样例

3

1 4 6

输出样例

10

import java.util.Scanner;

public class a砝码称重 {
    //N个砝码,总重量
    static int N,sum;
    //记录状态 dp
    static int[][] dp;
    //砝码数
    static int[] arr;

    public static void main(String[] args) {
        Scanner sc=new Scanner(System.in);
        N = sc.nextInt();
        sum = 0;
        arr = new int[N+1];
        //记录能称出的总数
        int ans = 0;
        for (int i = 1; i <= N; i++) {
            arr[i] = sc.nextInt();
            sum += arr[i];
        }
        //N+1
        dp = new int[N+1][sum*2];
        //选前i个砝码去称重
        for (int i = 1; i <= N; i++) {
            for (int j = 1; j <= sum; j++) {
                //模拟 1 4 6
                //i == 1 arr[i] = 1
                //j 从1到sum总重量开始遍历
                //j == 1 arr[1] = 1 成立
                //j == 2 状态转移 都不成立 下一轮
                //i == 2 arr[2] = 4
                //j == 1 dp[1][1] = 1 dp[1][abs(1-4)] = null dp[1][2 + 4] =null //j到36时赋值1下一轮
                if (arr[i] == j){
                    dp[i][j] = 1;
                }else {

                    //三种状态//不加砝码|做减法可能会负数abs|做加法  在上一组所有可能的基础上进行状态转移
                    // dp[i-1][j]把上一个砝码的值赋予这个砝码
                    dp[i][j] = dp[i-1][j] | dp[i-1][Math.abs(j-arr[i])] | dp[i-1][j+arr[i]];//如果其中有一个满足就等于1,表示可以称出
                }
            }
        }
        for (int j = 1; j <= sum; j++) {
            if(dp[N][j]==1)ans++;
        }
        System.out.println(ans+"");
    }
}