现在的位置: 首页 > 综合 > 正文

迷宫寻宝(一)bfs,注意搜索条件,有点儿技巧

2018年04月25日 ⁄ 综合 ⁄ 共 2963字 ⁄ 字号 评论关闭
描述

一个叫ACM的寻宝者找到了一个藏宝图,它根据藏宝图找到了一个迷宫,这是一个很特别的迷宫,迷宫里有N个编过号的门(N<=5),它们分别被编号为A,B,C,D,E.为了找到宝藏,ACM必须打开门,但是,开门之前必须在迷宫里找到这个打开这个门所需的所有钥匙(每个门都至少有一把钥匙),例如:现在A门有三把钥匙,ACM就必须找全三把钥匙才能打开A门。现在请你编写一个程序来告诉ACM,他能不能顺利的得到宝藏。

 

输入
输入可能会有多组测试数据(不超过10组)。
每组测试数据的第一行包含了两个整数M,N(1<N,M<20),分别代表了迷宫的行和列。接下来的M每行有N个字符,描述了迷宫的布局。其中每个字符的含义如下:
.表示可以走的路
S:表示ACM的出发点
G表示宝藏的位置
X表示这里有墙,ACM无法进入或者穿过。
A,B,C,D,E表示这里是门,a,b,c,d,e表示对应大写字母的门上的钥匙。
注意ACM只能在迷宫里向上下左右四个方向移动。

最后,输入0 0表示输入结束。

输出
每行输出一个YES表示ACM能找到宝藏,输出NO表示ACM找不到宝藏。
样例输入
4 4 
S.X. 
a.X. 
..XG 
.... 
3 4 
S.Xa 
.aXB 
b.AG 
0 0
样例输出
YES 
NO

这道题比较特殊的就是对门的处理,就是当前遇到门的时候有三种情况:

1.整张地图上都没有钥匙了。

2.已经找到该门对应的钥匙了。

3.可以找到该门对应的钥匙,但是当前的状态无法到达。

所以,需要将门的信息保存起来,等找到一个门所有的钥匙时,再把没有打开的门重新加入队列即可

 

import java.util.LinkedList;
import java.util.Queue;
import java.util.Scanner;
class doorposition
{
	int x,y;
}
class node
{
	int x,y;
	public node(int x,int y) {
		this.x=x;
		this.y=y;
	}
}
public class Main {
	static doorposition doorpositions[];
	static int keynumber[],startx,starty,endx,endy,line,row;
	static char map[][];
	static int directions[][]={{-1,0},{1,0},{0,-1},{0,1}};
	public static boolean overmap(int x,int y)
	{
		if(x<0||x>=line||y<0||y>=row)return true;
		else return false;
	}
	public static boolean finaljudge()
	{
		for(int i=0;i<5;i++)
			if(keynumber[i]!=0)return false;
		return true;
	}
	public static String bfs()
	{
		Queue<node>queue=new LinkedList<node>();
		node first=new node(startx, starty);
		queue.add(first);
		while(!queue.isEmpty())
		{
			first=queue.remove();
			//这里的finaljudge()判断条件容易忽略
			if(first.x==endx&&first.y==endy&&finaljudge())
				return "YES";
			//如果遇到的是钥匙,则总的钥匙数减1,当钥匙数为0时,将该钥匙对应的门所在的位置设置成不可访问的状态(‘X’)
			if(map[first.x][first.y]>='a'&&map[first.x][first.y]<='e'&&keynumber[map[first.x][first.y]-'a']>0)
			{
				keynumber[map[first.x][first.y]-'a']--;
				if(keynumber[map[first.x][first.y]-'a']==0)
				{
					node doors=new node(doorpositions[map[first.x][first.y]-'a'].x,doorpositions[map[first.x][first.y]-'a'].y);
					if(map[doors.x][doors.y]=='X')
						queue.add(doors);
				}
			}
			//当遇到门时,判断当前门对应的钥匙数,如果钥匙大于0,就说明到该门时,钥匙没有收集全,将门设置为不可访问状态
			if(map[first.x][first.y]>='A'&&map[first.x][first.y]<='E')
			{
				if(keynumber[map[first.x][first.y]-'A']>0)
				{
					map[first.x][first.y]='X';
					continue;
				}
				
			}
			//不是钥匙和门的情况,设置为不可访问状态
			map[first.x][first.y]='X';
			//四个方向进行搜索
			for(int i=0;i<4;i++)
			{
				node next=new node(first.x+directions[i][0], first.y+directions[i][1]);
				if(overmap(next.x,next.y)||map[next.x][next.y]=='X')continue;
				queue.add(next);
			}
		}
		return "NO";
	}
	public static void main(String[] args) {
		Scanner scanner=new Scanner(System.in);
		while(scanner.hasNext())
		{
			int i,j,k;
			line=scanner.nextInt();
			row=scanner.nextInt();
			if(line==0&&row==0)break;
			String strings[]=new String[line+4];
			map=new char[line+4][row+4];
			doorpositions=new doorposition[5];
			keynumber=new int[5];
			for(i=0;i<5;i++)
			{
				doorpositions[i]=new doorposition();
				keynumber[i]=0;
			}
			for(j=0;j<line;j++)
			{
				strings[j]=scanner.next();
				for(k=0;k<row;k++)
				{
					map[j][k]=strings[j].charAt(k);
					if(map[j][k]=='S')
					{
						startx=j;
						starty=k;
					}
					if(map[j][k]=='G')
					{
						endx=j;
						endy=k;
					}
					//记录钥匙数
					if(map[j][k]>='a'&&map[j][k]<='e')
					{
					    keynumber[map[j][k]-'a']++;	
					}
					//记录门的位置
					if(map[j][k]>='A'&&map[j][k]<='E')
					{
						doorpositions[map[j][k]-'A'].x=j;
						doorpositions[map[j][k]-'A'].y=k;
					}
					
				}
			}
			System.out.println(bfs());
		    
		}
	}
}
                        

抱歉!评论已关闭.