牛客网——逃离迷宫

这篇博客介绍了一个利用广度优先搜索(BFS)解决迷宫问题的算法。题目要求在给定的二维地图中,寻找从人物起点到出口的最短路径,途中可能需要收集钥匙。博主详细阐述了思路,即创建一个队列存储可行的节点,并考虑了扩展条件,如未拿到钥匙时不能访问终点。代码实现中,博主定义了Point类来存储节点信息,并通过检查函数确保搜索路径的合法性。最终,通过广搜遍历所有可能的路径,找到最短时间。
摘要由CSDN通过智能技术生成

题目

给你一个n*m的图,地图上’.‘代表可以走的地方,而’#'代表陷阱不能走,
'P’代表人物位置,'K’代表钥匙,'E’代表出口。人物一个,钥匙有多个,
('K’的数量<=50)),出口一个,每个位置可以向(上,下,左,右)四个
方向走一格,花费一个单位时间,现在你需要花费最少的时间拿到钥匙
然后从迷宫的出口出去(若没有钥匙,则不能进入迷宫出口所在的格子)。
题目传送门

思路

利用广搜来搜索,可以到达的点就加入队列,继续往下搜索即可。

注意扩展条件,除了要在地图的范围内,该节点要不就是没有被访问过,要不就是拿到了钥匙才可以访问第二次,而且,终点E在没有拿到钥匙的状态是不能够访问的。

所以,节点要有行坐标,列坐标,一个标记是否拿到钥匙,还有一个是步数。结合上面的条件,就可以解决问题了!

代码

import java.util.LinkedList;
import java.util.Queue;
import java.util.Scanner;

class Point{
    boolean isGetKey;
    int x;//行
    int y;//列
    int step;//步数
    public Point(int x,int y,boolean isGetKey,int step)
    {
        this.x=x;
        this.y=y;
        this.isGetKey=isGetKey;
        this.step=step;
    }
}

public class Main {
    static int n;//行
    static int m;//列
    static char map[][]=new char[510][510];
    static int visited[][]=new int[510][510];

    //人物位置的坐标
    static int P_x;
    static int P_y;

    //广搜队列
    static Queue<Point> queue=new LinkedList();

    //方向数组
    static int d_x[]={0,1,0,-1};
    static int d_y[]={1,0,-1,0};

    static int steps;
    static boolean isReach;

    public static void main(String[] args) {
        Scanner reader = new Scanner(System.in);
        int num=reader.nextInt();//测试的组数
        for (int g=0;g<num;++g)
        {
            n=reader.nextInt();//行
            m=reader.nextInt();//列
            String blank=reader.nextLine();//接收回车符

            //接收地图
            for (int i=0;i<n;++i)
            {
                String test=reader.next();
                for (int j=0;j<m;++j)
                {
                    map[i][j]=test.charAt(j);//填充地图
                    visited[i][j]=0;//初始化标记数组
                    //标记起始人物的位置
                    if (test.charAt(j)=='P')
                    {
                        P_x=i;
                        P_y=j;
                    }
                }
            }

            isReach=false;//初始化是否到达结点
            queue.clear();//清空队列

            Point a=new Point(P_x,P_y,false,0);
            ++visited[P_x][P_y];//走过一次
            queue.offer(a);
            while (!queue.isEmpty())
            {
                Point b=queue.poll();//弹出队首
                if (map[b.x][b.y]=='K')//先检验该节点是不是钥匙
                {
                    b.isGetKey=true;//拿到钥匙,改变当前节点和往后节点的钥匙状态
                }
                if (b.isGetKey && map[b.x][b.y]=='E') //钥匙拿到了并且到了终点
                {
                    isReach=true;
                    steps= b.step;
                    break;
                }
                for (int k=0;k<=3;++k)
                {
                    int temp_x=b.x+d_x[k];
                    int temp_y=b.y+d_y[k];
                    if (b.isGetKey && check(temp_x,temp_y)) //当前拿到钥匙,可以到达有终点的地方
                    {
                        Point l=new Point(temp_x,temp_y, true, b.step+1);
                        ++visited[temp_x][temp_y];
                        queue.offer(l);
                    }
                    if (!b.isGetKey && check2(temp_x,temp_y)) //当前没有拿到钥匙,终点E不可以走
                    {
                        Point l=new Point(temp_x,temp_y,false,b.step+1);
                        ++visited[temp_x][temp_y];
                        queue.offer(l);
                    }
                }
            }
            if (isReach)//在过程中到达终点
            {
                System.out.println(steps);
            }
            else
                System.out.println("No solution");
        }
    }
    //没有拿到钥匙,不可以访问终点E,第三个例子就是这样的
    public static boolean check(int a,int b)
    {
        return a>=0 && a<n && b>=0 && b<m && (map[a][b]=='.' || map[a][b]=='K' || map[a][b]=='E') && (visited[a][b]<=1);
    }

    //拿到了钥匙,才可以访问终点E
    public static boolean check2(int a,int b)
    {
        return a>=0 && a<n && b>=0 && b<m && (map[a][b]=='.'|| map[a][b]=='K') && visited[a][b]==0;
    }
}

结果

a了,不过太久没有做题了,一直很迷迷糊糊的,那个扩展条件也是想了很久才想清楚。

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值