2021年寒假每日一题,2017~2019年的省赛真题。
本文内容由倪文迪(华东理工大学计算机系软件192班)和罗勇军老师提供。
后面的每日一题,每题发一个新博文,请大家每天看博客蓝桥杯专栏: https://blog.csdn.net/weixin_43914593/category_10721247.html
提供C++、Java、Python三种语言的代码。
2018省赛A组第8题“全球变暖” ,题目链接:
http://oj.ecustacm.cn/problem.php?id=1365
https://www.dotcpp.com/oj/problem2276.html
1、题目描述
你有一张某海域NxN像素的照片,".“表示海洋、”#"表示陆地,如下所示:
.......
.##....
.##....
....##.
..####.
...###.
.......
其中"上下左右"四个方向上连在一起的一片陆地组成一座岛屿。例如上图就有2座岛屿。
由于全球变暖导致了海面上升,科学家预测未来几十年,岛屿边缘一个像素的范围会被海水淹没。
具体来说如果一块陆地像素与海洋相邻(上下左右四个相邻像素中有海洋),它就会被淹没。
例如上图中的海域未来会变成如下样子:
.......
.......
.......
.......
....#..
.......
.......
请你计算:依照科学家的预测,照片中有多少岛屿会被完全淹没。
输入:第一行包含一个整数N。 (1 <= N <= 1000) 。以下N行N列代表一张海域照片。 照片保证第1行、第1列、第N行、第N列的像素都是海洋。
输出:一个整数表示答案。
2、题解
题目一看就是“连通块问题”,是基础搜索。用DFS或BFS都行:遍历一个连通块(找到这个连通块中所有的’#‘,并标记已经搜过,不用再搜);再遍历下一个连通块…;遍历完所有连通块,统计有多少个连通块。
回到题目,什么岛屿不会被完全淹没?若岛中有个陆地(称为高地),它周围都是陆地,那么这个岛不会被完全淹没。
用DFS或BFS搜出有多少个岛(连通块),并且在搜索时统计那些没有高地的岛(连通块)的数量,就是答案。
因为每个像素点只用搜一次且必须搜一次,所以复杂度是 O ( N 2 ) O(N^2) O(N2)的,不可能更好了。
下面用C++代码实现DFS,用Python实现BFS,并附上Java代码。
3、DFS的C++代码
DFS所有的点,若遇到’#‘,就继续DFS这个’#‘周围的’#‘。把搜过的’#‘标记为已经搜过,不用再搜。标记那些没有高地的岛的数量,就是答案。
#include<bits/stdc++.h>
using namespace std;
int n;
char a[1010][1010]; //地图
int vis[1010][1010]={
0}; //标记是否搜过
int d[4][2] = {
{
0,1}, {
0,-1}, {
1,0}, {
-1,0}}; //四个方向
int flag; //用于标记这个岛中是否被完全淹没
void dfs(int x, int y){
vis[x][y] = 1; //标记这个'#'被搜过。注意为什么可以放在这里
if(a[x][y+1]=='#' && a[x][y-1]=='#' && a[x+1][y]=='#' && a[x-1][y]=='#')
flag = 1; //上下左右都是陆地,不会淹没
for(int i = 0; i < 4; i++){
//继续DFS周围的陆地
int nx = x + d[i][0], ny = y + d[i][1];
//if(nx>=1 && nx<=n && ny>=1 && ny<=n && vis[nx][ny]==0 && a[nx][ny]=='#') //题目说边上都是水,所以不用这么写了
if(vis[nx][ny]==0 && a[nx][ny]=='#') //继续DFS未搜过的陆地,目的是标记它们
dfs(nx,ny);
}
}
int main(){
cin >> n;
for(int i = 1; i <= n; i++)
for(int j = 1; j <= n; j++)
cin >> a[i][j];
int ans = 0 ;
for(int i = 1; i <= n; i++) //DFS所有像素点
for(int j = 1; j <= n; j++)
if(a[i][j]=='#' && vis[i][j]==0){
flag = 0;
dfs(i,j);
if(flag == 0) //这个岛全部被淹
ans++; //统计岛的数量
}
cout<<ans<<endl;
return 0;
}
4、BFS的Python代码
下面的代码实现了BFS。注意Python有两种队列实现方式:
(1)用queue实现队列操作,见下面的代码。
(2)Python的list就是一个普通队列,代码中的注释是用list实现的队列。
from queue import *
def bfs(x,y):
dirt=[(0,1),(0,-1),(1,0),(-1,0)]
q = Queue() #q = [(x,y)] #也可以用list来实现队列
q.put((x,y))
vis[x][y]=1
flag = 0
while not q.empty(): #while len(q)!=0:
current=q.get() #current=q.pop(0)
x,y=current[0],current[1]
if flag == 0:
if a[x][y+1]=='#' and a[x][y-1]=='#' and a[x+1][y]=='#' and a[x-1][y]=='#':
flag = 1 #这个岛不淹没
for i in range(4):
newx=x+dirt[i][0]
newy=y+dirt[i][1]
if vis[newx][newy]==0 and a[newx][newy]=="#":
q.put((newx,newy)) #q.append((newx,newy))
vis[newx][newy]=1 #注意为什么放在这里
if flag == 0: #这个岛被淹
return True
return False #这个岛不淹没
n=int(input())
a=[]
for i in range(n):
a.append(list(input()))
vis=[]
for i in range(n):
vis.append([0]*n)
ans=0
for i in range(n):
for j in range(n):
if vis[i][j]==0 and a[i][j]=="#":
if bfs(i,j): #这个岛被淹
ans+=1
print(ans)
5、Java代码
下面的Java代码实现了BFS。
//http://oj.ecustacm.cn/ User: 1840131230
import java.math.BigInteger;
import java.util.*;
public class Main
{
static class node{
int x,y;
node(int x,int y){
this.x=x;
this.y=y;
}
}
static int n,sums=0;
static char map[][];
static int vist[][];
static int dx[]= {
0,0,-1,1};
static int dy[]= {
-1,1,0,0};
static void bfs(int x,int y) {
Queue<node> que=new LinkedList<node>();
que.add(new node(x,y));
vist[x][y]=1;
boolean flag=true;
while(!que.isEmpty()) {
node p=que.remove();
int xx=p.x;
int yy=p.y;
int sum=0;
for(int i=0;i<4;i++) {
int xxx=xx+dx[i];
int yyy=yy+dy[i];
if(xxx>=0&&xxx<n&&yyy>=0&&yyy<n&&map[xxx][yyy]=='#') {
sum++;
}
}
if(sum==4)flag=false;
for(int i=0;i<4;i++) {
int xxx=xx+dx[i];
int yyy=yy+dy[i];
if(xxx>=0&&xxx<n&&yyy>=0&&yyy<n&&vist[xxx][yyy]==0&&map[xxx][yyy]=='#') {
vist[xxx][yyy]=1;
que.add(new node(xxx,yyy));
sum++;
}
}
}
if(flag)sums++;
}
public static void main(String[] args)
{
Scanner sc=new Scanner(System.in);
n=sc.nextInt();
map=new char[n][n];
vist=new int[n][n];
for(int i=0;i<n;i++) {
map[i]=sc.next().toCharArray();
}
for(int i=0;i<n;i++) {
for(int j=0;j<n;j++) {
if(map[i][j]=='#'&&vist[i][j]==0) {
bfs(i,j);
}
}
}
System.out.println(sums);
}
}