AcWing 1113. 红与黑( bfs , dfs 解法 )

题目:

有一间长方形的房子,地上铺了红色、黑色两种颜色的正方形瓷砖。

你站在其中一块黑色的瓷砖上,只能向相邻(上下左右四个方向)的黑色瓷砖移动。

请写一个程序,计算你总共能够到达多少块黑色的瓷砖。

输入格式

输入包括多个数据集合。

每个数据集合的第一行是两个整数 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;
    }
}

  • 9
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值