蓝桥杯31天冲刺之十一 [java]

文章目录

  • 天干地支(模拟)
  • 包子凑数(动态规划)
  • 求值(暴力)
  • 青蛙跳杯子(BFS)

天干地支(模拟)

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

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

这个题就是一个简单的模拟,唯一需要注意的就是再减法的过程中会出现负数,导致索引越界异常

我的处理方法是,首先计算目标年份与2020的差值,然后对60取余,这个应该很好理解,然后在计算天干的下标,在计算的时候,首先先对差值取余,保证其落在[-10,10],然后额外加了一个10,是为了调整范围在[0,20],这样就可以消除下标越界问题了,地支的下标计算同理,不过需要把10换成12

package daily;

import java.util.Scanner;

/**
 * https://www.lanqiao.cn/problems/1029/learning/
 * 
 * @author Jia
 *
 */
public class day3_18_1 {
	public static void main(String[] args) {
		String[] tianGan = { "jia", "yi", "bing", "ding", "wu", "ji", "geng", "xin", "ren", "gui" };
		String[] diZhi = { "zi", "chou", "yin", "mao", "chen", "si", "wu", "wei", "shen", "you", "xu", "hai" };
		int startYear = 2020;// 开始计算年份
		int tianGanIndex = 6;// 天干当前下标
		int diZhiIndex = 0;// 地支当前下标

		Scanner sc = new Scanner(System.in);
		int year = sc.nextInt();
		sc.close();

		int sub = (year - startYear) % 60;// 目标年份与当前年份的差值,可能为负数
		tianGanIndex = (tianGanIndex + 10 + sub % 10) % 10;// 这里额外加10是为了消除sub为负数并且绝对值比tianGanIndex大导致最后下标为负数的影响
		diZhiIndex = (diZhiIndex + 12 + sub % 12) % 12;// 和上面的同理
		System.out.println(tianGan[tianGanIndex] + diZhi[diZhiIndex]);

	}
}

包子凑数(动态规划)

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

题目链接:http://lx.lanqiao.cn/problem.page?gpid=T2824(先登录蓝桥账号,这题在训练系统中)

首先需要知道:如果输入的数目之间不是互质的,也就是说他们的最大公因数不是1,则拼不出来的包子数目一定是INF,例如2,4,6,最后肯定只能拼出来2的倍数的包子

然后就是利用dp求解结果了,从一个可以拼出来的数量出发(0),如果另一个数能从一个可以凑出来的数加上任一一笼包子的数目得到,那么这个数字也能拼出。利用这个递推公式就可以得到所有可以拼出来的数目了。

最后再遍历一遍统计一下有多少个数量不能拼出来就好了

package daily;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.StreamTokenizer;

/**
 * http://lx.lanqiao.cn/problem.page?gpid=T2824
 * 
 * @author Jia
 *
 */
public class day3_18_2 {
	static BufferedReader bf = new BufferedReader(new InputStreamReader(System.in));
	static StreamTokenizer in = new StreamTokenizer(bf);

	public static int nextInt() throws IOException {
		in.nextToken();
		return (int) in.nval;
	}

	public static void main(String[] args) throws IOException {
		int N = nextInt();
		int[] A = new int[N];
		A[0] = nextInt();
		int gcd = A[0];
		// 读取输入并且求所有数字的最大公约数
		for (int i = 1; i < A.length; i++) {
			A[i] = nextInt();
			gcd = gcd(gcd, A[i]);
		}

		if (gcd != 1) {
			// 如果最大公因式不是1的话,则可定无法组成所有的序列,例如2,4,6最大公因式为2,所以无法组成奇数
			System.out.println("INF");
			return;
		}

		// 动态规划求出可以拼出哪些数目
		boolean[] dp = new boolean[10000];
		dp[0] = true;
		for (int i = 0; i < A.length; i++) {
			for (int j = 0; j + A[i] < dp.length; j++) {
				if (dp[j]) {
					// 下标为当前值加上第i笼包子的数目,这种需求一定可以拼出来
					dp[j + A[i]] = true;
				}
			}
		}

		// 遍历一遍统计答案
		int ans = 0;
		for (int i = 0; i < dp.length; i++) {
			if (!dp[i]) {
				ans++;
			}
		}
		System.out.println(ans);

	}

	/**
	 * 获得输入两个数字的最大公因式
	 * 
	 * @param a
	 * @param b
	 * @return
	 */
	private static int gcd(int a, int b) {
		return b == 0 ? a : gcd(b, a % b);
	}
}

求值(暴力)

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

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

哎,开始还在想有没有什么比较巧妙的办法可以去做这个题,然后最后都失败了,最后还是乖乖的直接暴力循环了,对于填空题直接暴力也挺不错的hhh

直接判断一个数的因数个数是不是100,是的话直接输出就ok,速度还挺快的

呃,又想出来一种做法,可以建立一个数组,初始值为0,然后从1往后遍历,将其整数倍的位置的值都+1,然后找到第一个值为100的就是输出,但是有个问题就是不知道数组开多大,这就是纯纯的空间换时间了

package daily;

/**
 * https://www.lanqiao.cn/problems/816/learning/
 * 
 * @author Jia
 *
 */
public class day3_18_3 {
	public static void main(String[] args) {
		int num = 6;
		while (true) {
			if (getFactorNum(num) == 100) {
				System.out.println(num);
				break;
			}
			num++;
		}
	}

	/**
	 * 得到传入数字因数的个数
	 * 
	 * @param num
	 * @return
	 */
	private static int getFactorNum(int num) {
		int ans = 0;
		int end = (int) Math.sqrt(num);
		for (int i = 1; i < end; i++) {
			if (num % i == 0) {
				ans += 2;
			}
		}
		if (end == Math.sqrt(num)) {
			ans++;
		}
		return ans;
	}
}

青蛙跳杯子(BFS)

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

题目链接:http://lx.lanqiao.cn/problem.page?gpid=T2835 (先登录蓝桥账号,这题在训练系统中)

这个题主要使用的方法是BFS广度优先搜索,因为在广度优先搜索的情况下可以保证找到的第一个答案一定是最短的路径(所有情况走的步数都是相同的,一种找到,则一定都是最短的,深度优先则就不一定了),和前几天出现的迷宫问题类似

在具体的处理过程中,使用了数组去存储所有的情况,因为会存在两个元素交换位置(青蛙从一个杯子跳到另一个杯子,则原来的杯子就是空的了,类似于交换位置),数组处理起来比较方便一点,然后交换位置总共会有6种情况,空杯子的左边三个到右边三个都可能会和空杯子的位置交换(也就是题上说的可以直接跳,隔一个,隔两个),这里为了方便直接使用一个for循环做了。然后在加入队列的时候需要是把clone的版本加进去,因为数组其实一个引用类型(类似于C中的地址),如果不clone的话,最后所有数组都会是一个样子。

另外还加入了哈希集合去重,如果前面出现过得情况后面就没必要再去找了,哪怕这样会找到正确答案,但走的路也一定比前面出现的那次长。

还有一个小坑是比较数组相等的时候不要使用arr.equals()了,这玩意看了源码才知道比的是索引值,也就是指向的地址(实际上来说它没有重写Object类中的equals,所以才是这样判断的),判断两个数组是否相同需要使用Arrays.equals(arr1,arr2),这个类里面非常多好用的静态方法,有时间可以翻API手册看看

但是最后还是只通过了4/6的测试用例,最后俩超时了,但是从下载下来的测试用例来看答案是对的,不知道该咋优化了,等大佬们的题解出来再优化一下吧

这里附上倒数第二个测试用例:

输入:WWWWWWWW*BBBBBB *BBBBBBWWWWWWWW

输出:43

package daily;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.StreamTokenizer;
import java.util.Arrays;
import java.util.Deque;
import java.util.HashSet;
import java.util.LinkedList;
import java.util.Set;

/**
 * http://lx.lanqiao.cn/problem.page?gpid=T2835
 * 
 * @author Jia
 *
 */
public class day3_18_4 {
	static BufferedReader bf = new BufferedReader(new InputStreamReader(System.in));
	static StreamTokenizer in = new StreamTokenizer(bf);

	/**
	 * 快读按行读取模板
	 * 
	 * @return
	 */
	public static String nextLine() throws IOException {
		return bf.readLine();
	}

	public static void main(String[] args) throws IOException {
		String source = nextLine();
		String dest = nextLine();

		Deque<char[]> queue = new LinkedList<>();// 虚拟队列
		Set<String> set = new HashSet<>();// hashset用于去重
		char[] sourceArray = source.toCharArray();
		char[] destArray = dest.toCharArray();

		if (Arrays.equals(destArray, sourceArray)) {
			// 还没走就直接匹配到了
			System.out.println(0);
			return;
		}

		// 参数初始化
		queue.addFirst(sourceArray);
		set.add(source);
		int ans = 0;

		while (!queue.isEmpty()) {
			int size = queue.size();
			ans++;
			boolean flag = false;

			// 这里类似于层序遍历,需要统计跳了几步,所以在把上一次跳的所有情况处理完后步数才加一
			while (size > 0) {
				char[] chArr = queue.removeLast();

				int idx = getIdx(chArr);// 获取*的下标
				size--;

				// 把左边和后边的交换情况加入队列中
				for (int i = -3; i <= 3; i++) {
					if (i != 0 && idx + i >= 0 && idx + i < chArr.length) {
						char[] newArr = chArr.clone();
						swap(newArr, idx, idx + i);
						// 查重
						if (set.contains(String.valueOf(newArr))) {
							continue;
						}
						set.add(String.valueOf(chArr));
						if (Arrays.equals(destArray, newArr)) {
							flag = true;
							break;
						}
						queue.addFirst(newArr);
					}
				}

			}
			if (flag) {
				break;
			}
		}
		System.out.println(ans);
	}

	/**
	 * 交换传入数组中两元素的位置
	 * 
	 * @param chArr
	 * @param idx
	 * @param i
	 */
	private static void swap(char[] chArr, int idx, int i) {
		char temp = chArr[idx];
		chArr[idx] = chArr[i];
		chArr[i] = temp;
	}

	/**
	 * 获得数组中`*`的位置
	 * 
	 * @param chArr
	 * @return
	 */
	private static int getIdx(char[] chArr) {
		for (int i = 0; i < chArr.length; i++) {
			if (chArr[i] == '*') {
				return i;
			}
		}
		return -1;
	}
}

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