蓝桥杯2021年第十二届省赛真题-砝码称重
时间限制: 1Sec 内存限制: 128MB 提交: 1797 解决: 590
题目描述
你有一架天平和 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。
【评测用例规模与约定】
对于 50% 的评测用例,1 ≤ N ≤ 15。
对于所有评测用例,1 ≤ N ≤ 100,N 个砝码总重不超过 100000。
状态转移方程就是:
dp[i]的全部可能=dp[i-1]+和以前的加减新组合
代码实现:
import java.util.Scanner;
public class 砝码称重 {
static int N;
static int[] W;
static int COUNT;
public static void main(String[] args) {
Scanner scanner = new Scanner(System.in);
N = scanner.nextInt();
W = new int[N];
int sum = 0;
for (int i = 0; i < N; i++) {
sum += W[i] = scanner.nextInt();
}
COUNT = sum;
//Arrays.sort(W);
dpFaMa();
}
/*
状态转移方程就是:
dp[i]的全部可能=dp[i-1]+和以前的加减新组合
数组dp[i]的大小为全部砝码的总和 COUNT
*/
public static void dpFaMa() {
boolean[][] dp = new boolean[W.length][COUNT + 1];
for (int i = 0; i < W.length; i++) {
//对于dp数组的初始化 对于目标为0的配重 都置为true
// 对于每一行和砝码重量相同的目标配重也置为true
dp[i][0] = true;
dp[i][W[i]] = true;
}
//从第二块砝码开始递推
for (int i = 1; i < dp.length; i++) {
//第一列配重为0跳过
for (int j = 1; j < COUNT + 1; j++) {
//加当前砝码w[i]之前,就存在的;
if (dp[i - 1][j]) {
dp[i][j] = true;
}
//情况一:砝码和j在一起
if (W[i] + j <= COUNT && dp[i - 1][W[i] + j]) {
//当前砝码和目标都放到同一边,然后有已经可以测的重量在另一侧
//还有个限制,就是当前砝码,和当前测量j之和不能超过总重,即数组的总重;
//如果有的话,当前j就能true
dp[i][j] = true;
}
//情况二:砝码和j分开
if (dp[i - 1][Math.abs(j - W[i])]) {
//j可以被当前砝码和以前的砝码组成,
//或者j加以前的砝码等于当前砝码;
dp[i][j] = true;
}
}
}
int sum = 0;
for (int i = 1; i <= COUNT; i++) {
if (dp[N - 1][i]) {
sum++;
}
}
System.out.println(sum);
}
}
53.最大子数组和
题解:
package leetcode;
/**
* @Description:
* @Author Ladidol
* @Date: 2022/3/26 20:40
* @Version 1.0
*/
public class _53_最大子数组和 {
public static void main(String[] args) {
int[] nums = {-2,1,-3,4,-1,2,1,-5,4};
System.out.println(new 最大子数组和().maxSubArray(nums));
}
}
/**
* @Description:
* @Author: ladidol
* @Date: 2022/3/26 21:08
* @Param:
* @Return:
*/
class 最大子数组和 {
public int maxSubArray(int[] nums) {
//只有当以当前节点结尾的子节点,这样来考虑的话,才有dp的影子;
//当前节点是结尾or开始,max(dp[i]+nums[i],nums[i]);
//这里能取到当前节点的最优解了,但是下一个节点的最优解就要和最优解maxOld比较
int[] dp = new int[nums.length];
dp[0] = nums[0];
int max = nums[0];
for (int i = 1; i < nums.length; i++) {
dp[i] = Math.max(dp[i-1] + nums[i],nums[i]);
if (dp[i] > max){
max = dp[i];
}
}
return max;
}
}
70.爬楼梯和青蛙跳阶一样的
package leetcode;
import java.util.HashMap;
import java.util.Map;
/**
* @Description:
* @Author Ladidol
* @Date: 2022/3/25 15:00
* @Version 1.0
*/
public class _70_爬楼梯 {
public static void main(String[] args) {
System.out.println("爬十阶楼梯有 " + new 爬楼梯().climbStairs(10));
}
}
class 爬楼梯 {
public Map<Integer, Integer> note = new HashMap<> ();
public int climbStairs(int n) {
if( n <= 2){
return n;
}
//按这种,代表每一次分叉都会开启一次递归,有重复的递归
// return climbStairs( n - 1) + climbStairs( n - 2);
//按这种,代表每一个台阶都只开启一次递归
if (note.containsKey(n)){
return note.get(n);
}else {
note.put(n,climbStairs(n-1)+climbStairs(n-2));
return note.get(n);
}
}
}
300.最长递增子序列
package leetcode;
/**
* @Description:
* @Author Ladidol
* @Date: 2022/3/25 16:01
* @Version 1.0
*/
public class _300_最长递增子序列 {
public static void main(String[] args) {
int[] nums = {10,9,2,3,7,101,18};
System.out.println(new 最长递增子序列().lengthOfLIS(nums));
}
}
class 最长递增子序列 {
//dp(i) =max(dp(j))+1,
// 存在j属于区间[0,i-1],并且num[i]>num[j]。
public int lengthOfLIS(int[] nums) {
int[] dp = new int[nums.length];
int maxLen = 0;
for (int i = 0; i < nums.length; i++) {
dp[i] = 1;
for (int j = 0; j < i; j++) {
if(nums[i]>nums[j]){
//这里只能这样,因为,如果是元dp[i],就不加一
dp[i] = Math.max(dp[i], dp[j] + 1);
}
}
maxLen = Math.max(dp[i],maxLen);
}
return maxLen;
}
}
121.买股票最佳时机
package leetcode;
/**
* @Description:
* @Author Ladidol
* @Date: 2022/3/26 19:36
* @Version 1.0
*/
public class _121_买股票最佳时机 {
public static void main(String[] args) {
int[] nums1 = {7,1,5,3,6,4};
int[] nums2 = {7,6,4,3,1};
System.out.println(new 买股票().maxProfit(nums1));
}
}
class 买股票 {
public int maxProfit(int[] prices) {
//数组中存有当前的现金;
//每一个天有两个状态,持有股票1和没有持有股票0
//持有股票的情况来自于,今天买的or昨天及之前就买了的,然后天持有的股票一定是今天以前最低价买来的;
//没有股票的情况来自于,今天卖出去了股票or昨天及之前就卖了的
//dp[i][0]没持股票,dp[i][0]=max(dp[i-1][0],dp[i-1][1]+prices[i])
//dp[i][1]持有股票,dp[i][1]=max(dp[i-1][1],-prices[i])
int n = prices.length;
int[][] dp = new int[n][2];
dp[0][0] = 0;
dp[0][1] = -prices[0];
for(int i = 1 ; i< n; i++){
dp[i][0]=Math.max(dp[i-1][0],dp[i-1][1]+prices[i]);
dp[i][1]=Math.max(dp[i-1][1],-prices[i]);
}
return dp[n-1][0];
}
}
欢迎点赞关注哦!
也欢迎到访我的博客!小小的博客传送门!