题目
给你一个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了,不过太久没有做题了,一直很迷迷糊糊的,那个扩展条件也是想了很久才想清楚。