NYOJ 迷宫寻宝(一)

题目链接点击打开链接

迷宫寻宝(一)

时间限制: 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

思路:dfs+贪心?,从源点开始dfs,尽可能的走过更多的地方,拿到更多的钥匙,每一次dfs将拿到钥匙的点或已经打开的门都重置为空地,也就是将他们变为'.'  ,利用一个标记变量来记录每一次是否有新的进展,如果没有那么永远都不能拿到宝藏,如果有就继续dfs.

#include <bits/stdc++.h>
using namespace std;

char ma[25][25];
int n, m, gx, gy, mark;
int cnt[5];//a,b,c,d,e数量 
int fin[5];
bool vis[25][25];
bool val(int x, int y){
	if( x<1||x>n||y<1||y>m||ma[x][y]=='X'||!vis[x][y] )return false;
	return true;
}
void dfs(int curx, int cury){
	if( mark==1 )return;
	vis[curx][cury] = false;
	char t = ma[curx][cury];
	if( t>='a'&&t<='e' ){
		fin[t-'a']++;
		ma[curx][cury] = '.';
		if( mark!=1 ) mark = 0; 
	}
	if( t>='A'&&t<='E' ){
		if( fin[t-'A']==cnt[t-'A'] ){
			ma[curx][cury] = '.';
			if( mark!=1 ) mark = 0;
		}else return;
	}
	if( t=='G' ){
		mark = 1;
		return;
	}
	if( val(curx-1,cury) ) dfs(curx-1,cury);
	if( val(curx+1,cury) ) dfs(curx+1,cury);
	if( val(curx,cury-1) ) dfs(curx,cury-1);
	if( val(curx,cury+1) ) dfs(curx,cury+1);
}
void pt(){
	printf("ma:\n");
	for( int i = 1; i <= n; i++ ){
		for( int j = 1; j <= m; j++ ){
			printf("%c",ma[i][j]);
		}
		printf("\n");
	}
	printf("vis:\n");
	for( int i = 1; i <= n; i++ ){
		for( int j = 1; j <= m; j++ ){
			printf("%d ",vis[i][j]);
		}
		printf("\n");
	}
}
int main(){
	int x, y;
	while( scanf("%d%d",&n,&m)&&n+m ){
		memset( cnt, 0, sizeof(cnt) ); 
		memset( fin, 0, sizeof(fin) );
		memset( vis, true, sizeof(vis) );
		for( int i = 1; i <=n; i++ ){
			getchar();
			for( int j = 1; j <=m; j++ ){
				scanf("%c",&ma[i][j]);
				if( ma[i][j]>='a'&&ma[i][j]<='e' ){
					cnt[ma[i][j]-'a']++;
				}else if( ma[i][j]=='G' ){
					gx = i;gy = j;
				}else if( ma[i][j]=='S' ){
					x = i;y = j;
				}
			}
		}
		while( true ){
			mark = -1; //-1为初始状态,如果没变化 
			memset( vis, true, sizeof(vis) );
			dfs(x,y);
//			pt();
			if( mark==-1 ){
				printf("NO\n");
				break;
			}else if( mark==1 ){
				printf("YES\n");
				break;
			}
		}
	}
	
	return 0;
}


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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值