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

时间过去三分之二了,不知道大家刷的怎么样了,要继续坚持下去呀

七星填数字

如下图所示。在七角星的 1414 个节点上填入 11 ~ 1414的数字,不重复,不遗漏。 要求每条直线上的四个数字之和必须相等。

图中已经给出了 33 个数字。 请计算其它位置要填充的数字,答案唯一。

填好后,请输出绿色节点的 44 个数字(从左到右,用空格分开)。

image-20220327105234815

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

这个题也是直接爆搜了,首先使用回溯法的排列树找出所有的排列组合,然后找到七条边相等的情况就好了

题目中由于已经给出了三个固定的节点,因此把他们标号为1,2,3,这样就可以在找子集树的时候不破坏这三个的顺序了,然后check()中七条边是从节点4开始,顺时针找的,直到再次回到节点四,注意一定要把这里看清楚了,写完最好检查一遍,我检查时候就发现错了两三处,离谱。。。

package daily;

public class day3_27_1 {
	static int[] ans;
	static boolean flag;

	public static void main(String[] args) {
		int[] arr = { 6, 14, 11, 1, 2, 3, 4, 5, 7, 8, 9, 10, 12, 13 };
		backtrack(arr, 3);// 回溯找到所有排列方法
		for (int i = 3; i < 7; i++) {
			System.out.print(ans[i] + " ");
		}
	}

	private static void backtrack(int[] arr, int index) {
		if (index == arr.length) {
			check(arr);
		} else {
			for (int j = index; j < arr.length; j++) {
				if (!flag) {
					// 没有找到时候就继续找
					swap(arr, index, j);
					backtrack(arr, index + 1);
					swap(arr, index, j);
				}

			}
		}
	}

	/**
	 * 交换元素
	 * 
	 * @param arr
	 * @param i
	 * @param j
	 */
	private static void swap(int[] arr, int i, int j) {
		int temp = arr[i];
		arr[i] = arr[j];
		arr[j] = temp;
	}

	/**
	 * 检查七条边是否相等
	 * 
	 * @param arr
	 */
	private static void check(int[] arr) {
		int num1 = arr[3] + arr[4] + arr[5] + arr[6];
		int num2 = arr[6] + arr[8] + arr[10] + arr[13];
		int num3 = arr[13] + arr[11] + arr[9] + arr[1];
		int num4 = arr[1] + arr[7] + arr[4] + arr[0];
		int num5 = arr[0] + arr[5] + arr[8] + arr[2];
		int num6 = arr[2] + arr[10] + arr[11] + arr[12];
		int num7 = arr[12] + arr[9] + arr[7] + arr[3];
		if (num1 == num2 && num2 == num3 && num3 == num4 && num4 == num5 && num5 == num6 && num6 == num7) {
			ans = arr.clone();
			flag = false;
		}
	}
}

旋转

image-20220327132137722

题目链接:http://lx.lanqiao.cn/problem.page?gpid=T2705

这个直接模拟就好了,主要是需要自己画一个矩阵去推一下对应关系,下面的公式可以自己画个矩阵推导一下,尽量让m和n不要相等
rotatePic [ i ] [ j ] = pic [ j ] [ n − i − 1 ] \text{rotatePic}[i][j] = \text{pic}[j][n-i-1] rotatePic[i][j]=pic[j][ni1]

package daily;

import java.util.Scanner;

/**
 * http://lx.lanqiao.cn/problem.page?gpid=T2705
 * 
 * @author Jia
 *
 */
public class day3_27_2 {
	public static void main(String[] args) {
		Scanner sc = new Scanner(System.in);
		int n = sc.nextInt();
		int m = sc.nextInt();

		// 读入的时候直接旋转
		int[][] rotatePic = new int[m][n];
		for (int i = 0; i < n; i++) {
			for (int j = 0; j < m; j++) {
				rotatePic[j][n - i - 1] = sc.nextInt();
			}
		}
		sc.close();

		// 输出结果
		for (int i = 0; i < rotatePic.length; i++) {
			for (int j = 0; j < rotatePic[0].length; j++) {
				System.out.print(rotatePic[i][j] + " ");
			}
			System.out.println();
		}
	}
}

迷宫与陷阱

image-20220327142139206

题目链接:http://lx.lanqiao.cn/problem.page?gpid=T2760

有点迷茫hhh,这个题用的还是bfs,前面也做过比较简单的迷宫,这个题相比来说加了一个无敌时间和陷阱,稍微复杂一点,直接套模板写出来也能过30%的用例

然后最主要的就是constrains函数该怎么写,也就是如何判断下一格到底能不能走,我改来改去所有的用例都通过了,但是不是一个代码通过的hhhh,所有的都贴在代码里面了

  • 第一次通过了2356,其他答案错误,是因为没有考虑无敌可以回头走的情况,参考给出的测试用例一

  • 第二次通过了1234,其他超时,是因为我设置了如果是无敌,只要不是墙都可以走,然后就会导致无敌时间一直在走重复的格子,最后就炸了

  • 第三次除了测试用例4错误,6超时,其他都过了,这次又额外设置了一个状态数组,将无敌状态与非无敌状态走过的节点区分开了,分析用例可能是因为无敌状态时候把可以需要经过的节点走过一遍了,然后导致最后走不过去了,类似于下面这种情况,[0,1]的无敌把[2,3]的节点走过了,然后导致后面的无敌走不那一个格子了,其实我还在想可以对于每一次无敌状态设置一个状态数组,但是不知道怎么实现,就只能这样了,80%的通过率

    image-20220327141839868

package daily;

import java.util.Deque;
import java.util.LinkedList;
import java.util.Scanner;

/**
 * http://lx.lanqiao.cn/problem.page?gpid=T2760
 * 
 * @author Jia
 *
 */
public class day3_27_3 {
	public static void main(String[] args) {
		Scanner sc = new Scanner(System.in);
		int N = sc.nextInt();
		int K = sc.nextInt();

		char[][] maze = new char[N][N];
		for (int i = 0; i < N; i++) {
			String str = sc.next();
			for (int j = 0; j < N; j++) {
				maze[i][j] = str.charAt(j);
			}
		}
		sc.close();

		Deque<MazeNodeII> queue = new LinkedList<>();
		boolean[][] nodeStatus = new boolean[N][N];// 记录正常状态是否走过这个格子
		boolean[][] invincibleStatus = new boolean[N][N];// 记录无敌状态下是否走过这个格子
		queue.addLast(new MazeNodeII(0, 0, 0));
		nodeStatus[0][0] = true;

		int[] nextRow = { 0, -1, 0, 1 };
		int[] nextCol = { 1, 0, -1, 0 };
		int ans = 0;

		boolean flag = false;
		while (!queue.isEmpty()) {
			int size = queue.size();
			ans++;
			while (size > 0) {
				size--;
				MazeNodeII node = queue.removeFirst();

				for (int i = 0; i < nextCol.length; i++) {
					int newRow = node.row + nextRow[i];
					int newCol = node.col + nextCol[i];

					if (bound(N, newRow, newCol)
							&& constrains(maze, nodeStatus, invincibleStatus, node, newRow, newCol)) {
						if (newRow == N - 1 && newCol == N - 1) {
							// 到达终点直接返回
							flag = true;
							break;
						}
						if (node.time > 0) {
							invincibleStatus[newRow][newCol] = true;
						} else {
							nodeStatus[newRow][newCol] = true;
						}

						// 判断无敌时间
						int newTime = node.time > 0 ? node.time - 1 : 0;
						newTime = maze[newRow][newCol] == '%' ? K : newTime;

						// 加入节点
						queue.add(new MazeNodeII(newRow, newCol, newTime));

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

	/**
	 * 判断这一格能不能走
	 * 
	 * 如果当前是无敌状态,则只要下一格不是墙都可以走,不管以前有没有走过,这样可以回去把旁边是陷阱的路也加着
	 * 
	 * 如果当前不是无敌状态,则只能走没走过的路,并且下一格不是地('.')或者无敌('%')
	 * 
	 * @param maze
	 * @param nodeStatus
	 * @param invincibleStatus
	 * @param node
	 * @param newRow
	 * @param newCol
	 * @return
	 */
	private static boolean constrains(char[][] maze, boolean[][] nodeStatus, boolean[][] invincibleStatus,
			MazeNodeII node, int newRow, int newCol) {
		// 测试用例4错误,6超时,其他都过了
		return (node.time > 0 && invincibleStatus[newRow][newCol] == false && maze[newRow][newCol] != '#')
				|| (nodeStatus[newRow][newCol] == false
						&& (maze[newRow][newCol] == '.' || maze[newRow][newCol] == '%'));

		// 测试用例过了2356,其他答案错误
		// return nodeStatus[newRow][newCol] == false && (maze[newRow][newCol] == '.' ||
		// maze[newRow][newCol] == '%'
		// || node.time > 0 && maze[newRow][newCol] == 'X');

		// 测试用例过了1234,其他超时
		// return maze[newRow][newCol] != '#'
		// && (node.time > 0 || nodeStatus[newRow][newCol] == false &&
		// maze[newRow][newCol] != 'X');
	}

	/**
	 * 判断这一格是不是在迷宫的范围内
	 * 
	 * @param N
	 * @param newRow
	 * @param newCol
	 * @return
	 */
	private static boolean bound(int N, int newRow, int newCol) {
		return newRow >= 0 && newRow < N && newCol >= 0 && newCol < N;
	}
}

class MazeNodeII {
	int row;
	int col;
	int time;// 剩余无敌时间

	public MazeNodeII(int row, int col, int time) {
		super();
		this.row = row;
		this.col = col;
		this.time = time;
	}
}

九宫幻方

image-20220327142358994

题目链接:http://lx.lanqiao.cn/problem.page?gpid=T2832

这个题开始看到有点懵,不知道怎么做,然后觉得情况可能不是很多就想全部写出来,然后写出来又不知道全不全,最后就直接先写代码生成所有的方式,然后把他们都放在一个数组里,去匹配输入的情况

这个题最后提交的代码只用到了main中的部分,其余部分都是为了生成strs数组的。

思路就是将读入的串与可能存在的九宫格进行匹配,如果除0外的所有字符都匹配,那么就是一个可能的答案,然后统计答案个数再输出就ok了

package daily;

import java.util.HashSet;
import java.util.Scanner;
import java.util.Set;

/**
 * http://lx.lanqiao.cn/problem.page?gpid=T2832
 * 
 * @author Jia
 *
 */
public class day3_27_4 {
	static int[] nums = { 1, 2, 3, 4, 5, 6, 7, 8, 9 };
	static Set<String> set = new HashSet<>();

	public static void main(String[] args) {
		// getAllNums();
		String[] strs = { "438951276", "276951438", "618753294", "294753618", "492357816", "816357492", "834159672",
				"672159834" };
		Scanner sc = new Scanner(System.in);
		StringBuilder sb = new StringBuilder();
		for (int i = 0; i < 9; i++) {
			sb.append(sc.nextInt());
		}
		String input = sb.toString();

		int count = 0;// 满足条件的答案个数
		String ans = "";// 最后一个可以匹配的字符串
		for (String str : strs) {
			boolean flag = true;
			for (int j = 0; j < strs.length; j++) {
				if (input.charAt(j) == '0') {
					continue;
				}
				if (input.charAt(j) != str.charAt(j)) {
					flag = false;
					break;
				}
			}
			if (flag) {
				count++;
				ans = str;
			}
		}

		// 输出结果
		if (count == 1) {
			for (int i = 0; i < 3; i++) {
				System.out.println(ans.charAt(3 * i) + " " + ans.charAt(3 * i + 1) + " " + ans.charAt(3 * i + 2));
			}
		} else {
			System.out.println("Too Many");
		}
	}

	/**
	 * 生成所有可能的九宫格
	 */
	private static void getAllNums() {
		backtrack(0);
		System.out.println(set.size());
		String[] strs = set.toArray(new String[1]);
		for (int i = 0; i < strs.length; i++) {
			System.out.println(strs[i]);
		}
	}

	/**
	 * 回溯法生成所有的排列方式
	 * 
	 * @param i
	 */
	private static void backtrack(int i) {
		if (i == nums.length) {
			check();
		} else {
			for (int j = 0; j < nums.length; j++) {
				swap(j, i);
				backtrack(i + 1);
				swap(j, i);
			}
		}
	}

	/**
	 * 检查当前排列是否满足条件
	 */
	private static void check() {
		// 横着
		int num1 = nums[0] + nums[1] + nums[2];
		int num2 = nums[3] + nums[4] + nums[5];
		int num3 = nums[6] + nums[7] + nums[8];
		// 竖着
		int num4 = nums[0] + nums[3] + nums[6];
		int num5 = nums[1] + nums[4] + nums[7];
		int num6 = nums[2] + nums[5] + nums[8];
		// 对角线
		int num7 = nums[0] + nums[4] + nums[8];
		int num8 = nums[2] + nums[4] + nums[6];

		if (num1 == num2 && num1 == num3 && num1 == num4 && num1 == num5 && num1 == num6 && num1 == num7
				&& num1 == num8) {
			StringBuilder sb = new StringBuilder();

			for (int i = 0; i < nums.length; i++) {
				sb.append(nums[i]);
			}
			set.add(sb.toString());
		}
	}

	private static void swap(int j, int i) {
		int temp = nums[i];
		nums[i] = nums[j];
		nums[j] = temp;
	}
}

大臣的旅费

在这里插入图片描述

题目链接:http://lx.lanqiao.cn/problem.page?gpid=T2921

这个题我也不太会,但是找到了下面的结论:

假设 s-t这条路径为树的直径,或者称为树上的最长路,现有结论,从任意一点u出发搜到的最远的点一定是s、t中的一点,然后在从这个最远点开始搜,就可以搜到另一个最长路的端点,即用两遍dfs就可以找出树的最长路

在本题中,首先冲首都出发,找到距离首都最远的点(城市1),然后从这个最远的点出发,找到最远的点(城市2),那么城市1与城市2之间一定是整个地图上最远的,然后利用dfs搜索就ok了

但是我只过了四分之三的测试用例,最后一个用例超出内存限制了,看了测试用例,有10000个城市,所以要开一个10000*10000的数组,呃超出限制是正常的了hhhh,所以这个题应该是不能用矩阵去存路径的,改成关联矩阵应该就可以了,我把两种方法都写出来了有兴趣可以看看

  • 临接矩阵最后一个用例超出内存限制,通过75%
  • 关联矩阵通过100%

邻接矩阵法

package daily;

import java.util.Arrays;
import java.util.Scanner;

/**
 * http://lx.lanqiao.cn/problem.page?gpid=T2921
 * 
 * @author Jia
 *
 */
public class day3_27_5 {

	public static int[][] map;
	public static int[] vis;
	public static int ans = -1;// 最远路程
	public static int temp;// 距离首都最远的城市
	public static int n;// 城市数量

	public static void main(String[] args) {
		Scanner sc = new Scanner(System.in);
		n = sc.nextInt();
		map = new int[n + 1][n + 1];
		vis = new int[n + 1];
		for (int i = 0; i < n - 1; i++) {
			int num1 = sc.nextInt();
			int num2 = sc.nextInt();
			int len = sc.nextInt();
			map[num1][num2] = len;
			map[num2][num1] = len;
		}

		vis[1] = 1;
		dfs(1, 0);// 搜索距离首都最远的城市并存入temp中

		Arrays.fill(vis, 0);
		vis[temp] = 1;
		ans = -1;
		dfs(temp, 0);// 搜索距离temp最远的城市,也就是整个地图上相距最远的两个城市
		int sum = (11 + 10 + ans) * ans / 2;
		System.out.println(sum);
	}

	/**
	 * 搜索距离s的最长的路
	 * 
	 * @param s        起始点
	 * @param distance 距离
	 */
	static void dfs(int s, int distance) {
		if (distance > ans) {
			ans = distance;
			temp = s;
		}
		for (int i = 1; i <= n; i++) {
			if (vis[i] == 0 && map[s][i] > 0) {
				// 如果没有被访问过 而且s与i间的有路
				vis[i] = 1;
				distance += map[s][i];// 累加路程
				dfs(i, distance);// 从当前节点再继续搜索
				vis[i] = 0;
				distance -= map[s][i];
			}
		}
	}
}

关联矩阵法

package daily;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.Scanner;

/**
 * http://lx.lanqiao.cn/problem.page?gpid=T2921
 * 
 * @author Jia
 *
 */
public class day3_27_5_change {

	public static ArrayList<ArrayList<PathNode>> map;
	public static int[] vis;
	public static int ans = -1;// 最远路程
	public static int temp;// 距离首都最远的城市
	public static int n;// 城市数量

	public static void main(String[] args) {
		Scanner sc = new Scanner(System.in);
		n = sc.nextInt();
		map = new ArrayList<>();
		vis = new int[n + 1];
		for (int i = 0; i < n + 1; i++) {
			map.add(new ArrayList<>());
		}

		for (int i = 0; i < n - 1; i++) {
			int num1 = sc.nextInt();
			int num2 = sc.nextInt();
			int len = sc.nextInt();
			map.get(num1).add(new PathNode(num2, len));
			map.get(num2).add(new PathNode(num1, len));
		}
		sc.close();

		vis[1] = 1;
		dfs(1, 0);// 搜索距离首都最远的城市并存入temp中

		Arrays.fill(vis, 0);
		vis[temp] = 1;
		ans = -1;
		dfs(temp, 0);// 搜索距离temp最远的城市,也就是整个地图上相距最远的两个城市
		int sum = (11 + 10 + ans) * ans / 2;
		System.out.println(sum);

	}

	/**
	 * 搜索距离s的最长的路
	 * 
	 * @param s        起始点
	 * @param distance 距离
	 */
	static void dfs(int s, int distance) {
		if (distance > ans) {
			ans = distance;
			temp = s;
		}
		ArrayList<PathNode> paths = map.get(s);
		for (int i = 0; i < paths.size(); i++) {
			PathNode node = paths.get(i);
			if (vis[node.to] == 0) {
				// 如果没有被访问过 而且s与i间的有路
				vis[node.to] = 1;
				distance += node.distance;// 累加路程
				dfs(node.to, distance);// 从当前节点再继续搜索
				vis[node.to] = 0;
				distance -= node.distance;
			}
		}
	}
}

class PathNode {
	int to;
	int distance;

	public PathNode(int to, int distance) {
		super();
		this.to = to;
		this.distance = distance;
	}
}
  • 7
    点赞
  • 31
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Hydrion-Qlz

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值