文章涉及《算法导论》中广度优先搜索的介绍,以及相关题目的编程练习

编程题目

问题描述(华为2021年9月8号机试第二题)

一个M*N的网格,每个格子中的值表示从当前格子走最多可以跨几步(格子中的值为0表示该格子不可达),只能向右或者向下走。则从(0,0)开始走到(M-1,N-1)最少需要几步?

注:无法达到(M-1,N-1)最终输出-1

输入

3,3

3 2 2 0 1 0 1 1 1

说明:

  • 第一行输入网格的行和列,用逗号隔开。
  • 第二行依次输入各个格子的值,用空格隔开。

输出:2

基于bfs的代码实现

import java.util.*;
/*
测试用例
{3,2,2},
{0,1,0},
{1,1,1}

{3,2,2},
{0,1,0},
{1,1,0}

{3,2,2,3,4,5},
{0,1,1,1,2,2},
{1,2,3,1,1,1},
{1,2,3,1,1,1},
{1,2,3,1,1,1}
 */
public class Main{
    public static void main(String[] args) {
        int[][] matrix = new int[][]{
                {3,2,2},
                {0,1,0},
                {1,1,1}
        };
        //访问标记矩阵,用于标记节点的访问情况
        //visited=0表示白色,白色表示未被发现,初始化全部为白色
        //visited=1表示灰色,灰色表示已经被发现,但是还没有别访问
        //visited=2表示黑色,黑色表示已经被访问(与黑色节点相邻的节点都显示为灰色,即表示被发现)
        int[][] visited = new int[matrix.length][matrix[0].length];
        //访问距离矩阵,用于存放各个节点到源节点的距离。(这里应该将distance中的元素初始化为一个大的数。但这里为方便观察测试没有初始化)
        int[][] distance = new int[matrix.length][matrix[0].length];
        int result=bfs(matrix,visited,distance,0 , 0);
        System.out.println(result);
    }

    /**
     *
     * @param matrix   网格矩阵
     * @param visited  访问标记矩阵
     * @param distance 访问距离矩阵
     * @param x 初始节点的横坐标
     * @param y 初始点的纵坐标
     * @return 返回-1表示终点不可达,其他返回的是初始节点到节点的距离
     */
    private static int bfs(int [][]matrix,int[][]visited,int distance[][],int x,int y){
        //一、创建队列,用于存放被发现的节点
        Queue<String>queue=new LinkedList<>();

        //二、初始化
        int currDistance=0;
        queue.offer(x+" "+y);
        visited[x][y]=1;//初始节点设置为灰色,表示已经被发现
        distance[x][y]=currDistance;

        //三、访问队列中的节点
        while (queue.size()!=0){
            String curr[]=queue.poll().split(" ");//队列首部出队,以当前元素作为父节点遍历其子节点
            int parentX=Integer.parseInt(curr[0]);
            int parentY=Integer.parseInt(curr[1]);
            List<String>adjNodes=findAdjNodes(parentX,parentY,matrix);
            //当前距离是父节点的到初始节点的距离
            currDistance=distance[parentX][parentY];
            for (int i = 0; i <adjNodes.size() ; i++) {
                int childX=Integer.parseInt(adjNodes.get(i).split(" ")[0]);
                int childY=Integer.parseInt(adjNodes.get(i).split(" ")[1]);
                //队列中的元素都是灰色的且没有重复元素。所以只有当前节点是白色的才会添加到队列中
                if (visited[childX][childY]==0){
                    queue.offer(adjNodes.get(i));//入队
                    visited[childX][childY]=1;
                    distance[childX][childY]=currDistance+1;
                }
                //如果被发现的节点是终点,则直接输出该节点到初始节点的距离,该距离一定是最短的(广度优先遍历的特点决定)。
                if (childX==matrix.length-1&&childY==matrix[0].length-1){
                    System.out.println();
                    return distance[childX][childY];
                }
            }
            visited[parentX][parentY]=2;//当前节点作为父节点遍历完毕,将其设置为黑色

            //四、观察测试
            System.out.println("-------------------------------------------");
            System.out.println("访问标记矩阵的情况");
            for(int b[]:visited){
                System.out.println(Arrays.toString(b));
            }
            System.out.println("访问距离矩阵的情况");
            for(int b[]:distance){
                System.out.println(Arrays.toString(b));
            }
        }
        return -1;
    }

    /**
     *
     * @param x 当前节点的横坐标
     * @param y 当前节点的纵坐标
     * @param matrix 网格矩阵
     * @return 当前节点的邻接节点(即从当前节点出发可以达到的其他节点的集合)
     */
    private static List<String> findAdjNodes(int x,int y,int[][]matrix){
        int value=matrix[x][y];
        List<String>list=new ArrayList<>();
        //从(x,y)处向下找
        for (int i = y+1; i <matrix[0].length; i++) {
            if (i<=value+y&&matrix[x][i]!=0){
                list.add(x+" "+i);
            }
        }
        //从(x,y)处向右找
        for (int i = x+1; i <matrix.length; i++) {
            if (i<=value+x&&matrix[i][y]!=0){
                list.add(i+" "+y);
            }
        }
        return list;
    }
}

广度优先搜索(bfs)

《算法导论》中的介绍:

《算法导论》——广度优先搜索(bfs)_广度优先搜索

《算法导论》——广度优先搜索(bfs)_i++_02

《算法导论》——广度优先搜索(bfs)_算法导论_03

《算法导论》——广度优先搜索(bfs)_算法导论_04

小结

广度优先搜索能够找出从给定源节点到所有可以到达的节点之间的距离,可以用于计算源节点到终点的最短路径。