前言
这一届的蓝桥杯题目是出名的难(希望今年不会创下新高-_-)
坑 简介
- 判断陆地会不会淹没是个小坑,判断当前陆地是否会淹没的背景是其他陆地都还存在
- 另一个坑是有些小岛在经历全球变暖后会分裂成多个小岛,所以结果并不是淹没后的小岛个数减去之前的小岛个数。有些熟悉Floodfill算法求图的子图个数的大佬就看着坑就跳下去了。
- 还有一个涉及效率问题的,使用strs.charAt(index) 遍历的效率很低。可以使用char[]chs = str.toCharArray(), 亲测相比于第一种快了不少。
标题:全球变暖
你有一张某海域NxN像素的照片,".“表示海洋、”#"表示陆地,如下所示:
.......
.##....
.##....
....##.
..####.
...###.
.......
其中"上下左右"四个方向上连在一起的一片陆地组成一座岛屿。例如上图就有2座岛屿。
由于全球变暖导致了海面上升,科学家预测未来几十年,岛屿边缘一个像素的范围会被海水淹没。具体来说如果一块陆地像素与海洋相邻(上下左右四个相邻像素中有海洋),它就会被淹没。
例如上图中的海域未来会变成如下样子:
.......
.......
.......
.......
....#..
.......
.......
请你计算:依照科学家的预测,照片中有多少岛屿会被完全淹没。
【输入格式】
第一行包含一个整数N。 (1 <= N <= 1000)
以下N行N列代表一张海域照片。
照片保证第1行、第1列、第N行、第N列的像素都是海洋。
【输出格式】
一个整数表示答案。
【输入样例】
7
.......
.##....
.##....
....##.
..####.
...###.
.......
【输出样例】
1
资源约定:
峰值内存消耗(含虚拟机) < 256M
CPU消耗 < 1000ms
请严格按要求输出,不要画蛇添足地打印类似:“请您输入…” 的多余内容。
所有代码放在同一个源文件中,调试通过后,拷贝提交该源码。
不要使用package语句。不要使用jdk1.7及以上版本的特性。
主类的名字必须是:Main,否则按无效代码处理。
如何解决?
1. 我们首先要解决如何求子图的个数
其实这个算法就是借助图的遍历,dfs或者bfs
每遍历一个节点就设置为true, 可以使用boolean[][] jug; jug[i][j]=true
实现
由于执行一次dfs可以将当前节点的所有连接点遍历一遍,并设置为true。
int con=0;
for(int i=2; i<=n; i++)
for(int j=2; j<=n; j++) {
if(!jug[i][j]) // 如果当前节点没有访问过
dfs(i,j);
con++;
}
}
}
con即为子图个数。
解题思路
首先我们要小获取那些陆地被淹没了,boolean[][] jug; jug[i][j]=true
jug[i][j] 为true即表示当前陆地被淹没了,这样做的好处是不用新建一个char数组保存淹没后的图了,
那么如何获取淹没的小岛的个数呢,答案遍历
这里我们产生了二个图,
一个是淹没后的图由jug数组保存,true表示陆地,这个图就是由淹没后的陆地组成的。为了描述方便我们简称为pic1
另一是淹没前的原图,简称为pic2 chs保存
下面就是对着二个图的遍历了
flag2 = new boolean[n+1][n+1]; //第二个图的遍历访问标志
flag = new boolean[n+1][n+1]; // 第一个图的遍历访问标志
int con=0; // 记录最终的结果
for(int i=2; i<=n; i++) {
for(int j=2; j<=n; j++) { // 因为二个图一样大所以可以同时遍历
if(jug[i][j] && !flag2[i][j]) { //
cona=1; // 当前节点在pic1图中所有连接点的个数
conb=1; // 当前节点在pic2图中所有连接点的个数
dfs2(i,j); // conb flag2 第二个图遍历 淹没前的陆地组成的图
dfs(i,j); // cona flag 第一个图遍历 淹没的陆地组成的图
//如果淹没的节点个小岛消失了数等于原有陆地的个数
//那么就说明这个陆地所在的小岛消失了
if(cona==conb) con++;
}
}
}
这个解法核心就是遍历的这个节点所在的小岛的陆地个数,与这个节点所在小岛淹没陆地个数是否相等,想的则这个小岛消失
全部的代码
import java.util.Scanner;
public class Main
static int n,cona=0,conb=0;;
static char[][] chs;
static boolean[][] jug,flag,flag2;
public static void main(String[] args) {
Scanner scanner = new Scanner(System.in);
n = Integer.parseInt(scanner.next());
chs = new char[n+1][n+1];
for(int i=1; i<=n; i++) {
String str2 = " " + scanner.next() + " ";
chs[i] = str2.toCharArray();
}
jug = new boolean[n+1][n+1];
for(int i=2; i<=n; i++) {
for(int j=2; j<=n; j++) {
if(chs[i][j]=='#') {
if(chs[i-1][j]=='.' || chs[i][j+1]=='.' || chs[i+1][j]=='.'
||chs[i][j-1]=='.') {
jug[i][j] = true;
}
}
}
}
flag2 = new boolean[n+1][n+1];
flag = new boolean[n+1][n+1];
int con=0;
for(int i=2; i<=n; i++) {
for(int j=2; j<=n; j++) {
if(jug[i][j] && !flag2[i][j]) {
cona=1;conb=1;
dfs2(i,j);
dfs(i,j);
if(cona==conb) con++;
}
}
}
System.out.println(con);
}
// 遍历上下左右是个位置
static int xx[] = {-1, 0, 1, 0};
static int yy[] = {0,1,0,-1};
public static void dfs(int x, int y) {
if(x>n && y>n) return;
flag[x][y]=true;
for(int i=0; i<4; i++) {
if(x+xx[i]>=2 && x+xx[i]<=n-1 && y+yy[i]>=2 && y+yy[i]<=n-1) {
int a = x+xx[i];
int b = y+yy[i];
if(jug[a][b] && !flag[a][b]) {
dfs(a,b);
cona++;
}
}
}
}
public static void dfs2(int x, int y) {
if(x>n && y>n) return;
flag2[x][y]=true;
for(int i=0; i<4; i++) {
if(x+xx[i]>=2 && x+xx[i]<=n-1 && y+yy[i]>=2 && y+yy[i]<=n-1) {
int a = x+xx[i];
int b = y+yy[i];
if(chs[a][b] == '#' && !flag2[a][b]) {
dfs2(a,b);
conb++;
}
}
}
}
}
测试用例一个八个过了七个,可能是递归的问题,ac的大佬请不吝赐教
需要测试数据的,评论留言