蓝桥别31天冲刺之十四 [java]

今天就做了1,2,3,感觉还是不太理解二分的思想,碰到这种二分想的就是暴力做了,先放着吧,把动态规划刷完回来看二分怎么做

带分数(全排列)

image-20220321151229036

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

这个题首先分析一下它的算式,需要的结果是需要找到a,b,c,使得对于给定的N,有 N = a + b / c N=a+b/c N=a+b/c成立,并且a,b,c中每一位数字都不相同,这样就可以变成一个全排列问题,我们首先需要得到九位数的所有排列情况,然后在排列情况中再进行按不同的划分方式划分为3个不同数字,然后去判断是否符合上面给定的式子。

首先全排列的话可以使用dfs直接得到全排列的式子,然后在找到一种全排列的情况后对当前的排列进行划分,按照顺序划分为3个数字,然后判断等式是否成立,如果成立,则答案加一,否则直接遍历下一种情况

package daily;

import java.util.Scanner;

/**
 * https://www.lanqiao.cn/problems/208/learning/
 * 
 * @author Jia
 *
 */
public class day3_21_1 {
	static int ans = 0;
	static int N;
	static int[] arr = { 1, 2, 3, 4, 5, 6, 7, 8, 9 };

	public static void main(String[] args) {
		Scanner sc = new Scanner(System.in);
		N = sc.nextInt();
		sc.close();

		backtrack(0);
		System.out.println(ans);
	}

	/**
	 * dfs遍历得到所有的排列情况
	 * 
	 * @param index
	 */
	private static void backtrack(int index) {
		if (index == arr.length) {
			// 找到了一种排列方式
			check();
		} else {
			for (int i = index; i < arr.length; i++) {
				swap(i, index);
				backtrack(index + 1);
				swap(i, index);
			}
		}
	}

	/**
	 * 判断在当前这种排列情况下是否可以找到满足条件的a,b,c
	 */
	private static void check() {
		// N = a + b/c 转化为判断 N*c == a*c + b
		for (int i = 0; i <= 6; i++) {
			for (int j = i + 1; j <= 7; j++) {
				int a = getVal(0, i);
				int b = getVal(i + 1, j);
				int c = getVal(j + 1, 8);
				if (N * c == a * c + b) {
					ans++;
				}
			}
		}
	}

	/**
	 * 获得数组指定区间中拼接的数字,范围是:[i,j]
	 * 
	 * @param i
	 * @param j
	 * @return
	 */
	private static int getVal(int i, int j) {
		int count = 0;
		for (int k = i; k <= j; k++) {
			count = count * 10 + arr[k];
		}
		return count;
	}

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

}

走迷宫(bfs)

image-20220321134822638

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

这个题也比较常规,前面已经见过好多了,直接bfs遍历,然后统计走了几步就行了

和前面出现的非常类似,可以直接当做模板背过了,解析的话参考这个题迷宫,这里就不重复写了

唯一要注意的点就是这个题里面的最后一行的输入的坐标是从1开始的,对应到矩阵里面需要 - 1 然后才对应实际的坐标

package daily;

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

/**
 * https://www.lanqiao.cn/problems/1216/learning/
 * 
 * @author Jia
 *
 */
public class day3_21_2 {
	static BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
	static StreamTokenizer in = new StreamTokenizer(br);

	/**
	 * java快读模板
	 * 
	 * @return
	 * @throws IOException
	 */
	static int nextInt() throws IOException {
		in.nextToken();
		return (int) in.nval;
	}

	public static void main(String[] args) throws IOException {
		int N = nextInt();
		int M = nextInt();

		int[][] maze = new int[N][M];
		for (int i = 0; i < N; i++) {
			for (int j = 0; j < M; j++) {
				maze[i][j] = nextInt();
			}
		}
		boolean[][] meet = new boolean[N][M];// 标记是否看过这个这字,防止重复遍历
		MazeNode begin = new MazeNode(nextInt() - 1, nextInt() - 1);// 开始节点
		MazeNode end = new MazeNode(nextInt() - 1, nextInt() - 1);// 结束节点

		int ans = 0;
		Deque<MazeNode> deque = new LinkedList<>();
		deque.addLast(begin);
		meet[begin.row][begin.col] = true;

		int[][] direction = { { 1, 0 }, { 0, -1 }, { -1, 0 }, { 0, 1 } };// 4个方向
		boolean flag = false;
		while (!deque.isEmpty()) {
			int size = deque.size();
			ans++;
			while (size > 0) {
				size--;
				MazeNode node = deque.removeFirst();
				for (int i = 0; i < direction.length; i++) {
					// 遍历四个方向
					int newRow = node.row + direction[i][1];
					int newCol = node.col + direction[i][0];

					// 判断是不是在界内并且这个格子有路且没有看过
					if (newRow >= 0 && newRow < N && newCol >= 0 && newCol < M && maze[newRow][newCol] == 1
							&& meet[newRow][newCol] == false) {
						MazeNode newNode = new MazeNode(newRow, newCol);
						meet[newRow][newCol] = true;// 标记为已经看过了
						deque.addLast(newNode);

						if (end.equals(newNode)) {
							// 表示找到了终止节点直接退出循环
							flag = true;
							break;
						}
					}
				}
				if (flag) {
					break;
				}
			}
			if (flag) {
				break;
			}
		}
		System.out.println(flag ? ans : -1);
	}
}

// 节点类
class MazeNode {
	int row;
	int col;

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

	public boolean equals(MazeNode obj) {
		return row == obj.row && col == obj.col;
	}
}

蓝桥幼儿园(并查集)

image-20220321135245650

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

这个题用到了并查集的知识,我也不是很会,也是现学直接用的,这玩意也就是一个模板可以直接背过了用就行,我以为有现成的API,找了找发现没有,然后就看博客去啃了,参考的是这篇博客,感觉很清楚,如果不会的话可以去看看

实现并查集常用的比较简单的有两种方法,一种是不带路径压缩(左图),一种带路径压缩(右图),说白了讲就是要不要把原来节点的老大也换掉(不明白去看看上面那个博客),如果换掉的话查找的时间肯定会缩短,对于比较大的数据集可以大大减少查找时间

image-20220321143321617

这个题本身也不是很难,主要是对并查集基本操作的考察,希望可以记下,最好是直接背过

package daily;

import java.util.Scanner;

public class day3_21_3 {
	static int[] searchSet;

	public static void main(String[] args) {
		Scanner sc = new Scanner(System.in);
		int N = sc.nextInt();
		int M = sc.nextInt();

		searchSet = new int[N + 1];
		init(searchSet);
		for (int i = 0; i < M; i++) {
			int op = sc.nextInt();
			int x = sc.nextInt();
			int y = sc.nextInt();

			if (op == 1) {
				// 交朋友
				join(x, y);
			} else {
				// 判断是否是朋友
				int xParent = find_compact(x);
				int yParent = find_compact(y);
				System.out.println(xParent == yParent ? "YES" : "NO");
			}
		}
		sc.close();
	}

	/**
	 * 将x,y所在的集合合并
	 * 
	 * @param x
	 * @param y
	 */
	private static void join(int x, int y) {
		int xParent = find_compact(x);
		int yParent = find_compact(y);
		if (xParent < yParent) {
			searchSet[yParent] = xParent;
		} else {
			searchSet[xParent] = yParent;
		}
	}

	/**
	 * 判断两个数是否在同一个集合中, 不带路径压缩
	 * 
	 * @param x
	 */
	private static int find(int x) {
		return searchSet[x] == x ? x : find(searchSet[x]);
	}

	/**
	 * 判断两个数是否在同一个集合中, 带路径压缩
	 * 
	 * @param x
	 */
	private static int find_compact(int x) {
		return searchSet[x] == x ? x : (searchSet[x] = find_compact(searchSet[x]));
	}

	/**
	 * 设置每个人和自己在一个集合中
	 * 
	 * @param child
	 */
	private static void init(int[] child) {
		for (int i = 0; i < child.length; i++) {
			child[i] = i;
		}
	}
}

跳石头(贪心+二分)

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

  • 7
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 4
    评论
评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

Hydrion-Qlz

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

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

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

打赏作者

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

抵扣说明:

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

余额充值