大家好,我是snippet,今天是刷蓝桥真题的第十九天,这几天的难度逐渐上升,后面两个题都有点难顶了,一点点啃吧,今天前面两个题都可以用dfs来解决,下面是我今天前面两个题的题解
目录
一、灌溉
题目内容:
题目描述
小蓝负责花园的灌溉工作。
花园可以看成一个 n 行 m 列的方格图形。中间有一部分位置上安装有出水管。
小蓝可以控制一个按钮同时打开所有的出水管,打开时,有出水管的位置可以被认为已经灌溉好。
每经过一分钟,水就会向四面扩展一个方格,被扩展到的方格可以被认为已经灌溉好。即如果前一分钟某一个方格被灌溉好,则下一分钟它上下左右的四个方格也被灌溉好。
给定花园水管的位置,请问 k 分钟后,有多少个方格被灌溉好?
输入描述
输入的第一行包含两个整数 n,m。
第二行包含一个整数 t,表示出水管的数量。
接下来 t 行描述出水管的位置,其中第 i 行包含两个数 r,c 表示第 r 行第 c 列有一个排水管。
接下来一行包含一个整数 k。
其中,1≤n,m≤100,1≤t≤10,1≤k≤100。
输出描述
输出一个整数,表示答案。
输入输出样例
示例 1
输入
3 6
2
2 2
3 4
1输出
9
运行限制
- 最大运行时间:1s
- 最大运行内存: 128M
解题思路:
因为当我们将数据输入的时候就代表着开始计时了,刚开始就灌溉了方格,我们就先对其上下左右四个点进行灌溉,我们再根据时间的剩余,对已经灌溉的方格的周围的上下左右方格进行灌溉
代码:
package 蓝桥杯31天真题冲刺.Day19;
import java.io.*;
/**
* @author snippet
* @data 2023-03-22
* 灌溉-蓝桥云课
*/
// dfs
public class T1_灌溉 {
static BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
static PrintWriter pw = new PrintWriter(new BufferedWriter(new OutputStreamWriter(System.out)));
static int n,m,t,k,ans;
static int N = 110;
static boolean[][] a = new boolean[N][N];// 二维数组a,若为true则表示i行j列被灌溉了,反之没有灌溉
static int[] dx = {0, 0, -1, 1};
static int[] dy = {-1, 1, 0, 0};
static void dfs(int x, int y) {
a[x][y] = true;
for (int i = 0; i < 4; i++) {
if (x + dx[i] > 0 && x + dx[i] <= n && y + dy[i] > 0 && y + dy[i] <= m && a[x+dx[i]][y+dy[i]] == false) {
a[x+dx[i]][y+dy[i]] = true;
}
}
}
public static void main(String[] args) throws IOException {
String[] s = br.readLine().split(" ");
n = Integer.parseInt(s[0]);
m = Integer.parseInt(s[1]);
t = Integer.parseInt(br.readLine());
for (int i = 1; i <= t; i++) {
s = br.readLine().split(" ");
int r = Integer.parseInt(s[0]);
int c = Integer.parseInt(s[1]);
dfs(r, c);// 输入即灌溉
}
k = Integer.parseInt(br.readLine());
while (k > 1) {
int time = k - 1;
while (time-- > 0) {
for (int i = 1; i <= n; i++) {
for (int j = 1; j <= m; j++) {
if (a[i][j]) {
dfs(i, j);
}
}
}
}
}
for (int i = 1; i <= n; i++) {
for (int j = 1; j <= m; j++) {
if (a[i][j]) ans++;
}
}
pw.println(ans);
pw.flush();
br.close();
}
}
二、小朋友崇拜圈
题目链接:小朋友崇拜圈 - 蓝桥云课 (lanqiao.cn)
题目内容:
题目描述
班里 N 个小朋友,每个人都有自己最崇拜的一个小朋友(也可以是自己)。
在一个游戏中,需要小朋友坐一个圈,每个小朋友都有自己最崇拜的小朋友在他的右手边。
求满足条件的圈最大多少人?
小朋友编号为 1,2,3,⋯N。
输入描述
输入第一行,一个整数 N(3<N<105)。
接下来一行 N 个整数,由空格分开。
输出描述
要求输出一个整数,表示满足条件的最大圈的人数。
输入输出样例
示例
输入
9
3 4 2 5 3 8 4 6 9输出
4
样例解释
如下图所示,崇拜关系用箭头表示,红色表示不在圈中。
显然,最大圈是[2 4 5 3] 构成的圈。
运行限制
- 最大运行时间:1s
- 最大运行内存: 256M
解题思路:
因为合法的结果的前提是这个小朋友可以形成一个环,我们先记录下小朋友与小朋友之间的联系,对每个小朋友进行一次搜索遍历,在搜索的过程中如果该小朋友已经被遍历了,那就更新最大圈的人数的个数,退出循环,如果未被标记,那开始对下一个节点进行递归,递归完一个环之后记得回溯,把每个点的标记回未遍历
代码:
package 蓝桥杯31天真题冲刺.Day19;
import java.io.*;
/**
* @author snippet
* @data 2023-03-22
* 小朋友崇拜圈-蓝桥云课
*/
// dfs
public class T2_小朋友崇拜圈 {
static BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
static PrintWriter pw = new PrintWriter(new BufferedWriter(new OutputStreamWriter(System.out)));
static int n,start,ans;// n表示数据的个数 start表示环的开头 ans表示最大的环的长度
static int N = 100100;
static int[] a = new int[N];// 一维数组a表示i-->a[i]
static boolean[] vis = new boolean[N];// 一维数组vis,若为true表示已经遍历,反之未遍历
/**
* dfs搜索环
* @param x
* @param cnt 环的长度
*/
static void dfs(int x, int cnt) {
if (vis[x]) {
if (a[x] == a[start]) {
ans = Math.max(ans, cnt);
}
return;
}
vis[x] = true;
// 递归
dfs(a[x], cnt+1);
// 回溯
vis[x] = false;
}
public static void main(String[] args) throws IOException {
// 数据输入
String[] s = br.readLine().split(" ");
n = Integer.parseInt(s[0]);
s = br.readLine().split(" ");
for (int i = 1; i <= n; i++) {
a[i] = Integer.parseInt(s[i-1]);
}
// 将每个位置设置为开头进行一次递归搜索
for (int i = 1; i <= n; i++) {
start = i;
dfs(i, 0);
}
pw.println(ans);
pw.flush();
br.close();
}
}