洛谷 砝码称重
目录
题目描述
你有一架天平和 ( N ) 个砝码,这 ( N ) 个砝码重量依次是 ( W_1, W_2, \dots, W_N )。请你计算一共可以称出多少种不同的重量?注意砝码可以放在天平两边。
示例
示例 1
输入:
3
1 4 6
输出:
10
解释:
能称出的 10 种重量是:1、2、3、4、5、6、7、9、10、11。
思路分析
问题核心
我们需要计算使用 ( N ) 个砝码,通过将它们放在天平的两边,可以称出多少种不同的重量。
思路拆解
- 初始化:
- 使用一个集合
set
来记录所有可能的重量,初始时集合中只有 0。
- 使用一个集合
- 遍历砝码:
- 对于每个砝码,更新集合
set
,将当前砝码的重量加到集合中的每个元素上,或者从集合中的每个元素中减去当前砝码的重量。
- 对于每个砝码,更新集合
- 统计结果:
- 最终集合
set
的大小减去 1(去掉 0)就是可以称出的不同重量的数量。
- 最终集合
代码段
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashSet;
import java.util.Scanner;
import java.util.Set;
public class Main {
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
int n = sc.nextInt();
int[] dp = new int[n];
for (int i = 0; i < n; i++) {
dp[i] = sc.nextInt();
}
sc.close();
Arrays.sort(dp);
Set<Integer> set = new HashSet<>();
set.add(0);
for (int i = 0; i < dp.length; i++) {
ArrayList<Integer> list = new ArrayList<>(set);
for (int j : list) {
set.add(j + dp[i]);
set.add(Math.abs(j - dp[i]));
}
}
System.out.println(set.size() - 1);
}
}
代码逐行讲解
-
输入处理:
Scanner sc = new Scanner(System.in); int n = sc.nextInt(); int[] dp = new int[n]; for (int i = 0; i < n; i++) { dp[i] = sc.nextInt(); } sc.close(); Arrays.sort(dp);
- 使用
Scanner
读取输入的整数n
和n
个砝码的重量,并存储在数组dp
中。 - 对数组
dp
进行排序。
- 使用
-
初始化集合:
Set<Integer> set = new HashSet<>(); set.add(0);
- 初始化一个集合
set
,并添加初始值 0。
- 初始化一个集合
-
遍历砝码:
for (int i = 0; i < dp.length; i++) { ArrayList<Integer> list = new ArrayList<>(set); for (int j : list) { set.add(j + dp[i]); set.add(Math.abs(j - dp[i])); } }
- 对于每个砝码,遍历集合
set
中的每个元素,将当前砝码的重量加到元素上,或者从元素中减去当前砝码的重量,并将结果添加到集合set
中。
- 对于每个砝码,遍历集合
-
输出结果:
System.out.println(set.size() - 1);
- 输出集合
set
的大小减去 1(去掉 0)作为结果。
- 输出集合
复杂度分析
时间复杂度
- 遍历每个砝码的时间复杂度为 O(N)。
- 对于每个砝码,遍历集合
set
的时间复杂度为 O(M),其中 ( M ) 是集合set
的大小。 - 因此,总时间复杂度为 O(N * M)。
空间复杂度
- 使用了一个集合
set
来存储所有可能的重量,空间复杂度为 O(M),其中 ( M ) 是集合set
的大小。
总结的知识点
-
输入处理:
- 使用
Scanner
读取输入,并处理整数和数组。
- 使用
-
集合操作:
- 使用
HashSet
来存储和更新所有可能的重量。
- 使用
-
遍历与更新:
- 使用
for
循环遍历砝码和集合set
,并根据砝码的重量更新集合。
- 使用
-
数学计算:
- 使用
Math.abs
计算绝对值,确保重量的非负性。
- 使用
整合
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashSet;
import java.util.Scanner;
import java.util.Set;
public class Main {
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
int n = sc.nextInt();
int[] dp = new int[n];
for (int i = 0; i < n; i++) {
dp[i] = sc.nextInt();
}
sc.close();
Arrays.sort(dp);
Set<Integer> set = new HashSet<>();
set.add(0);
for (int i = 0; i < dp.length; i++) {
ArrayList<Integer> list = new ArrayList<>(set);
for (int j : list) {
set.add(j + dp[i]);
set.add(Math.abs(j - dp[i]));
}
}
System.out.println(set.size() - 1);
}
}
总结
我们掌握了如何使用集合来记录所有可能的重量,并通过遍历和更新集合来计算可以称出的不同重量的数量。关键点包括:
- 使用
HashSet
来存储和更新重量。 - 遍历砝码和集合,并根据砝码的重量更新集合。
- 使用
Math.abs
确保重量的非负性。