蓝桥杯31天冲刺之三 [java]

文章目录

  • 年龄巧合
  • 纸牌三角形
  • 取球游戏

年龄巧合

题目链接:https://www.lanqiao.cn/problems/694/learning/

蓝桥杯31天冲刺之三 [java]_第1张图片

这一个题对于年龄的计算是当前年份减出生年份,因此只需要从当前年份往前遍历即可

由于小明和表弟都是这样的,再加上小明肯定比表弟大,所以应该取第二个符合条件的年份输出即可(这里我也不能理解,俩人为啥不能一年生的,或许是因为周岁?不理解)

package daily;

/**
 * https://www.lanqiao.cn/problems/694/learning/
 * 
 * @author Jia
 *
 */
public class day3_10_1 {
	public static void main(String[] args) {
		int N = 2014;
		int k = 0;// 由于小明肯定比表弟大,因此应该取的是更早的年份(很离谱的是为啥他俩不能一年生的)
		for (int i = N - 1; i > 1900; i--) {
			int yearSum = getYearSum(i);
			// 如果找到符合条件的就可以直接记录
			if (2014 - i == yearSum) {
				k++;
				// 当找到第二个的时候就是小明的出生日期
				if (k == 2) {
					System.out.println(i);
					break;
				}
			}
		}
	}

	/**
	 * 获得传入数字的按位和
	 * 
	 * @param i
	 * @return
	 */
	private static int getYearSum(int i) {
		int sum = 0;

		while (i > 0) {
			sum += i % 10;
			i = i / 10;
		}
		return sum;
	}
}

纸牌三角形

题目链接:https://www.lanqiao.cn/problems/639/learning/

蓝桥杯31天冲刺之三 [java]_第2张图片

这个题就是典型的回溯法,又属于回溯法中的排列问题(另一个经典的是子集问题),对于这类问题,我们需要清楚的记住回溯法的模板,然后套进去就ok了

在这个题中,我将三角形拆开来,看做是一个数组,可以认为是从这里劈了一刀,将整个三角形分为两个部分,因此在统计有效结果的时候,条件就是前四个元素之和 = 中间4个元素之和 = 后三个元素+第一个元素之和,只有满足这个条件才会计入我们的有效统计中

蓝桥杯31天冲刺之三 [java]_第3张图片

在最后输出的时候,由于为了消除旋转和镜像的结果,我们需要除以6,得到最终结果。

这里可能有同学不明白为什么要除以6,我们可以把每三个元素看为一组,然后总共是三组在排列组合,总共就有6种情况,所以需要除以6

package daily;

public class day3_10_2 {
	static int ans = 0;

	public static void main(String[] args) {
		int[] nums = { 1, 2, 3, 4, 5, 6, 7, 8, 9 };
		backtrace(nums, 0);
		System.out.println(ans / 6);// 3个数字总共有六种排列,这里是为了去掉重复的情况
	}

	/**
	 * 开始回溯
	 * 
	 * @param nums
	 * @param i
	 */
	private static void backtrace(int[] nums, int i) {
		if (i == nums.length - 1) {
			// 进入这里说明是进入了最后一个节点
			// 统计各边之和
			int a = nums[0] + nums[1] + nums[2] + nums[3];
			int b = nums[3] + nums[4] + nums[5] + nums[6];
			int c = nums[6] + nums[7] + nums[8] + nums[0];
			// 如果各边之和相等则说明找到了一种符合条件的排列
			if (a == b && b == c) {
				ans++;
			}
		} else {
			// 对剩余的部分做排列继续回溯
			for (int j = i; j < nums.length; j++) {
				swap(nums, j, i);
				backtrace(nums, i + 1);
				swap(nums, j, i);
			}
		}
	}

	/**
	 * 交换数组中两个元素的位置
	 * 
	 * @param nums
	 * @param j
	 * @param i
	 */
	private static void swap(int[] nums, int j, int i) {
		int temp = nums[i];
		nums[i] = nums[j];
		nums[j] = temp;
	}
}

取球游戏

题目链接:https://www.lanqiao.cn/problems/278/learning/

蓝桥杯31天冲刺之三 [java]_第4张图片

这个题是一个典型的动态规划题,在这类题中,我们只要找到了递归式,题基本就出来了一大半

在该题中,我们使用一个数组记录当前角色在剩余棋子为index个时是否能获胜(因为题目中说两个角色都不会犯错,那么肯定都是最好的情况,如果能赢则一定会赢),因此,我们可以得到这个题的递归式,我们为了要赢,那么肯定是要在我们这一步走过去的那个地方为false,也就是到对面的回合时,他脚下是false,这样就可以保证我们当前脚下是true,那么这一步可以跨多大呐?按照题上说的,可以是1,3,7,8四种情况,那么我们只要看在这四种情况我们一步跨过去的地方是不是false,如果有一个是的话,那么我们就可以赢(只要拿对应的球,对手正在开始时脚下就已经是false,无论怎么走都是输),如果全是true,那么就必输了

经过上面的分析,我们就可以只用生成一个结果数组,然后用来记录轮到某个人的回合时他能不能赢(true为可以,false为不可以),当然如果轮到自己的回合,剩下的球为0的时候就已经获胜了,所以 result[0] 初始化为 true;

还有一个小trick是,我们这次依然是使用了一个数组去记录下一步可以走向哪里,这个方法我们在前天的题目灌溉中也用过了,用它的好处是可以很好的简化代码,并且方便数据的调整。虽然你不用也行,可以直接写死到代码里面,四个if既可以搞定,如果他可以迈出100种不同的步幅,难道我们写100个循环吗,或者是步幅需要从输入中读入,这时候该怎么办呐

package daily;

import java.util.Scanner;

public class day3_10_3 {
	public static void main(String[] args) {
		Scanner sc = new Scanner(System.in);
		int n = sc.nextInt();
		int max = 0;
		int[] nums = new int[n];
		for (int i = 0; i < n; i++) {
			int num = sc.nextInt();
			max = Math.max(max, num);
			nums[i] = num;
		}
		sc.close();

		boolean[] result = new boolean[max + 1];// 存储结果
		generateResult(result);// 生成最后结果
		// System.out.println(Arrays.toString(result));

		// 最后输出结果,由于结果数组是布尔类型的,需要转换为整数
		for (int i = 0; i < nums.length; i++) {
			int out = result[nums[i]] ? 1 : 0;
			System.out.println(out);
		}
	}

	private static void generateResult(boolean[] result) {
		int[] step = { 1, 3, 7, 8 };// 记录下步幅,方便直接用for循环做了,不然又是4个if,和昨天灌溉的题一样,巧用数组减少if,精简代码
		result[0] = true;
		for (int i = 0; i < result.length; i++) {
			for (int j = 0; j < step.length; j++) {
				// 如果这一步走出去,目标地点是false的话,说明走这一步可以保证自己赢
				if (i - step[j] >= 0 && result[i - step[j]] == false) {
					result[i] = true;
					break;
				}
			}
		}
	}
}

你可能感兴趣的:(蓝桥杯,蓝桥杯,算法,java)