题目:
有一间长方形的房子,地上铺了红色、黑色两种颜色的正方形瓷砖。
你站在其中一块黑色的瓷砖上,只能向相邻(上下左右四个方向)的黑色瓷砖移动。
请写一个程序,计算你总共能够到达多少块黑色的瓷砖。
输入格式
输入包括多个数据集合。
每个数据集合的第一行是两个整数 W 和 H,分别表示 x 方向和 y方向瓷砖的数量。
在接下来的 H 行中,每行包括 W 个字符。每个字符表示一块瓷砖的颜色,规则如下
1)‘.’:黑色的瓷砖;
2)‘#’:红色的瓷砖;
3)‘@’:黑色的瓷砖,并且你站在这块瓷砖上。该字符在每个数据集合中唯一出现一次。
当在一行中读入的是两个零时,表示输入结束。
输出格式
对每个数据集合,分别输出一行,显示你从初始位置出发能到达的瓷砖数(记数时包括初始位置的瓷砖)。
数据范围
1≤W,H≤201≤𝑊,𝐻≤20
输入样例:
6 9
....#.
.....#
......
......
......
......
......
#@...#
.#..#.
0 0
输出样例:
45
思路:
一。 bfs宽搜
第一步:理解题意
看了题目就是会给出多组案例,以0,0表示案例结束,在0,0之前需要给出每组案例的' . '的数量。而每组案例会给出h行w列的矩阵,包含一个‘@’为起点,' . '和‘#’(#号我们这里叫墙)。
第二步:思考
1. 因为可以走上下左右四个方向,我先想到定义这样两个数组
static int[] dx={0,1,0,-1};//四个方向 static int[] dy={1,0,-1,0};//右(0,1),下(1,0)左(0,-1)上(-1,0)
到时候只要走的时候遍历四个方向,再加上一些判断条件,再来判断这一步是不是真的可以走。
2. 如果符合条件可以走呢?我们要怎么来实现走的这一步?因此我就想到了队列,每次如果符合条件可以走我们就把当前的坐标x,y入队,再定义一个计数的,这样每走一步就是出队和入队。有了想法说肝就肝。
import java.io.*;
import java.util.LinkedList;
import java.util.Queue;
public class Main{
static int h,w;//h行w列
static int N=30;
static Point start;
static int[] dx={0,1,0,-1};
static int[] dy={1,0,-1,0};
static char[][] map=new char[N][N];//矩阵用于存储数据
static BufferedReader br=new BufferedReader(new InputStreamReader(System.in));
public static void main(String[] args) throws Exception{
String[] strings=br.readLine().split(" ");
w=Integer.parseInt(strings[0]);
h=Integer.parseInt(strings[1]);
while(true) { //只有(w==0&&h==0) 才会退出循环
if(w==0&&h==0) break;
for(int i=0;i<h;i++) {
char[] chars=br.readLine().toCharArray();
for(int j=0;j<w;j++) {
map[i][j]=chars[j];
if(map[i][j]=='@') start=new Point(i, j);//找到起点
}
}
System.out.println(bfs(start));
strings=br.readLine().split(" ");//下一次的
w=Integer.parseInt(strings[0]);
h=Integer.parseInt(strings[1]);
}
br.close();
}
private static int bfs(Point start) {
Queue<Point> queue=new LinkedList<>();//新建一个队列
queue.add(start);//将起点入队
int res=0;//步数也就是 ’ . ‘ 的个数
while(!queue.isEmpty()) { //当队列非空
Point t=queue.poll();//队头出队
res++;//队头出队同时步数+1
for(int i=0;i<4;i++) { // 往四个方向走
int x=t.x+dx[i];
int y=t.y+dy[i];
if(x<0||x>=h||y<0||y>=w||map[x][y]!='.') continue; //边界或者下一步不是'.'就下一个方向看看
map[x][y]='#';// 走到这说明符合要求,标记为'#'墙
queue.add(new Point(x, y));//再把这个点入队
}
}
return res;//返回数量
}
static class Point{// 对应结构体
int x;
int y;
public Point(int x,int y) {
this.x=x;
this.y=y;
}
}
}
二。 dfs深搜
后面想着应该也可以用dfs来遍历,知道起点之后就可以往里面一层一层搜
思路和dfs差不多,只是不再需要要队列来记录了,详细的在代码有加上注释
import java.io.*;
public class Main{
static int h,w,x,y;//h行w列
static int N = 30;
static int[] dx={0,1,0,-1};//四个方向
static int[] dy={1,0,-1,0};
static char[][] map = new char[N][N];//矩阵用于存储数据
static BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
public static void main(String[] args) throws Exception{
String[] strings = br.readLine().split(" ");
w = Integer.parseInt(strings[0]);//h行w列
h = Integer.parseInt(strings[1]);
while(true) {
if(w==0&&h==0) break;
for(int i=0;i<h;i++) {
char[] chars=br.readLine().toCharArray();//字符串转字符数组
for(int j=0;j<w;j++) {
map[i][j]=chars[j];
if(map[i][j]=='@') {//标记起点
x=i;
y=j;//记录起点的x和y
}
}
}
System.out.println(dfs(x, y));
strings = br.readLine().split(" ");//下一次
w=Integer.parseInt(strings[0]);
h=Integer.parseInt(strings[1]);
}
br.close();
}
private static int dfs(int x,int y) {
int ans=1;//当前起点已经算一个了,题目有说
map[x][y]='#';//标记为墙
for(int i=0;i<4;i++) {//依然是四个方向遍历
int a = x + dx[i];
int b = y + dy[i];
if(a<0 || a>=h || b<0 || b>=w || map[a][b]!='.') continue;
//走到这说明边界和墙的问题都符合,继续往下一层搜
ans += dfs(a, b);
}
return ans;
}
}