nyoj82(迷宫寻宝)

nyoj82(迷宫寻宝)

迷宫寻宝(一)

时间限制: 1000 ms  |  内存限制: 65535 KB
难度: 4
描述

一个叫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.每层先判断当前位置的信息

(1).为'.'继续搜索周围

(2).为‘X’返回

(3).为’A‘-’E'保存门的信息(注意不要标记X,如果标记将来就无法访问此门了,会被覆盖)

(4).为‘a’-‘e’钥匙++

3.在最后查看门能否打开,如果可以打开就搜索门的周围,并标记X

4.重复2.3直到找到出口或者无路可走


#include <stdio.h>
#include <memory.h>

int key[6];
int keyNow[6];

struct Lock
{
	int x, y;
	int num;
};
Lock lock[6];
char map[22][22];
char dir[4][2] = {{0,1},{1,0},{0,-1},{-1,0}};
int w, h, sx, sy, ex, ey;
bool flag;
void dfs(int x, int y);

inline bool canMove(int x, int y)		// 能否移动
{
	return !(x<0||x>=w||y<0||y>=h);
}

void checkLock()
{
	int nx, ny;
	for (int i=0; i<5; ++i)
	{
		if ((keyNow[i]>0) && (keyNow[i] == key[i]) && lock[i].num > 0)	// 判断是否找齐钥匙
		{
			map[lock[i].y][lock[i].x] = 'X';		// 只有找到钥匙才能通过门
			for (int j=0; j<4; ++j)
			{
				nx = lock[i].x+dir[j][0];
				ny = lock[i].y+dir[j][1];
                if (canMove(nx, ny))
				    dfs(nx, ny);			// 从门的周围开始搜索
			}
		}
	}
}

void dfs(int x, int y)
{
	if (flag)			// 已经找到
		return;
	if (x==ex && y==ey)	//
	{
		flag = true;
		puts("YES");
		return;
	}
	if (map[y][x] == 'X')		// 此路不通
	{
		return;
	}
	if (map[y][x]>='a' && map[y][x]<='e')			// 钥匙++
	{
		keyNow[map[y][x]-'a']++;
	}
	else if (map[y][x]>='A' && map[y][x]<='E')		// 记录门的坐标
	{
		lock[map[y][x]-'A'].num++;
		lock[map[y][x]-'A'].x = x;
		lock[map[y][x]-'A'].y = y;
		return;		// 必须返回, 目的是防止深度搜的时候,再次遇到相同的门覆盖此次位置
	}
	map[y][x] = 'X';
	int nx, ny;
	for (int i=0; i<4; ++i)
	{
		nx = x+dir[i][0];
		ny = y+dir[i][1];
		if (canMove(nx, ny))
		{
			dfs(nx, ny);		// 搜索周围
		}
	}
	checkLock();	// 检查门能否打开并继续搜索
}

int main()
{
	while (scanf("%d%d", &h, &w) && (h||w))
	{
		getchar();
		memset(key, 0, sizeof(key));
		memset(keyNow, 0, sizeof(keyNow));
		memset(lock, 0, sizeof(lock));
		for (int i=0; i<h; ++i)
		{
			for (int j=0; j<w; ++j)
			{
				scanf("%c", &map[i][j]);
				if (map[i][j]>='a' && map[i][j]<='e')
				{
					key[map[i][j]-'a']++;		// 保存钥匙的个数
				}
				else if (map[i][j] == 'S')
				{
					sx = j;
					sy = i;
					map[i][j] = '.';
				}
				else if (map[i][j] == 'G')
				{
					ex = j; ey = i;
					map[i][j] = '.';
				}
			}
			getchar();
		}
		flag = false;
		dfs(sx, sy);
		if (!flag)
			puts("NO");
	}
	return 0;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值