迷宫寻宝(一)
时间限制:1000 ms | 内存限制:65535 KB
难度:4
描述
一个叫ACM的寻宝者找到了一个藏宝图,它根据藏宝图找到了一个迷宫,这是一个很特别的迷宫,迷宫里有N个编过号的门(N<=5),它们分别被编号为A,B,C,D,E.为了找到宝藏,ACM必须打开门,但是,开门之前必须在迷宫里找到这个打开这个门所需的所有钥匙(每个门都至少有一把钥匙),例如:现在A门有三把钥匙,ACM就必须找全三把钥匙才能打开A门。现在请你编写一个程序来告诉ACM,他能不能顺利的得到宝藏。
输入
输入可能会有多组测试数据(不超过10组)。
每组测试数据的第一行包含了两个整数M,N(1
输出
每行输出一个YES表示ACM能找到宝藏,输出NO表示ACM找不到宝藏。
样例输入
4 4
S.X.
a.X.
..XG
….
3 4
S.Xa
.aXB
b.AG
0 0
样例输出
YES
NO
思路
调了一个中午终于AC了不过代码已经丑的我自己都看不下去了,和标程一比简直都不能看人家的代码又少运行效率又高,归根结底还是思路的问题。所以说一道题目花一些时间思考找到一个好的思路还是很重要的。先说我的思路吧,因为看到数据并不大(20*20最多也就四百)就想着纯粹的把找钥匙开门的过程模拟一遍,输入的时候将各个钥匙的数量记录下来,先把能拿到的钥匙拿完,如果有某个门可以开了就把这个门全变成路,因为地图更新了嘛,然后再把上面的过程重复一遍,一直到拿不到钥匙或者找到宝藏。说着就极其麻烦所以导致代码同样极其复杂。
我的代码
#include <iostream>
#include <stdio.h>
#include <cstring>
#include <queue>
using namespace std;
char cha[]={'A','B','C','D','E'};
char t[30][30];
int a,b,c,d,e;
int m,n,bj;
int vis[30][30]={0};
int dir[4][2]={{0,1},{0,-1},{-1,0},{1,0}};
struct zuobiao{
int x,y;
int sum;
}p,k;
queue<zuobiao>q;
int gai() //判断某种钥匙是否已经全部到手,返回全部拿到的钥匙编号
{
if(a==0)
{a=-1;return 0;}
if(b==0)
{b=-1;return 1;}
if(c==0)
{c=-1;return 2;}
if(d==0)
{d=-1;return 3;}
if(e==0)
{e=-1;return 4;}
return -1;
}
int pan(char ch)//判断是否可以通过,路、钥匙、宝藏都是可以通过
{
if(t[k.x][k.y]=='.'
||t[k.x][k.y]=='a'
||t[k.x][k.y]=='b'||t[k.x][k.y]=='c'
||t[k.x][k.y]=='d'||t[k.x][k.y]=='e'
||t[k.x][k.y]=='G')
return 1;
return 0;
}
int key_jian(char ch)//判断当前块儿是否为钥匙,是的话相应钥匙数量-1,并返回真
{
if(ch=='a')a--;
else if(ch=='b')b--;
else if(ch=='c')c--;
else if(ch=='d')d--;
else if(ch=='e')e--;
else return 0;
return 1;
}
void key(char ch)//输入时保存钥匙数量
{
if(ch=='a')a++;
else if(ch=='b')b++;
else if(ch=='c')c++;
else if(ch=='d')d++;
else if(ch=='e')e++;
}
void bfs(int q_x,int q_y,int z_x,int z_y)//广搜
{
memset(vis,0,sizeof(vis));
while(!q.empty())q.pop();
p.x=q_x;
p.y=q_y;
p.sum=0;
q.push(p);
vis[p.x][p.y]=1;
while(!q.empty())
{
p=q.front();
q.pop();
if(p.x==z_x&&p.y==z_y)//遇到宝藏输出YES
{
cout<<"YES"<<endl;
t[z_x][z_y]='X';
bj=0;
return ;
}
for(int i=0;i<4;i++)
{
k.x=p.x+dir[i][0];
k.y=p.y+dir[i][1];
if(k.x>=0&&k.x<m&&k.y>=0&&k.y<n&&
(pan(t[k.x][k.y]))&&vis[k.x][k.y]==0)
{
if(key_jian(t[k.x][k.y]))//判断是否为钥匙相应钥匙-1并标记为路
t[k.x][k.y]='.';
vis[k.x][k.y]=1;
q.push(k);
}
}
}
int linshi=gai();//判断此次搜索是否有能开的门
if(linshi>=0)
{
for(int i=0;i<m;i++)
for(int j=0;j<n;j++)
{
if(t[i][j]==cha[linshi])
{
t[i][j]='.';
}
}
}
}
int main()
{
int q_x,q_y,z_x,z_y,w;
while(cin>>m>>n,m+n)
{
bj=1;
a=b=c=d=e=0;
for(int i=0;i<m;i++)
for(int j=0;j<n;j++)
{
cin>>t[i][j];
if(t[i][j]=='S')
{
q_x=i;q_y=j;
}
if(t[i][j]=='G')
{
z_x=i;z_y=j;
}
key(t[i][j]);
}
for(int i=0;i<6&&bj==1;i++)
{
bfs(q_x,q_y,z_x,z_y);
}
if(bj)
cout<<"NO"<<endl;
}
return 0;
}
标程
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<queue>
using namespace std;
struct node
{
int x;
int y;
}n1,n2;
int dx[4]={0,0,1,-1};
int dy[4]={1,-1,0,0};
int k[6];
int m,n;
int begin_x,begin_y;
char map[25][25];
bool vis[25][25];
bool judge(int x,int y)
{
if(x<0||x>=m||y<0||y>=n||vis[x][y]) return false;
if(map[x][y]=='X') return false;
if(map[x][y]>='a'&&map[x][y]<='e') k[map[x][y]-'a']--;
return true; //其他的所有情况都返回true,都要加入队列
}
bool bfs()
{
memset(vis,false,sizeof(vis));
queue<node>q;
n1.x=begin_x;
n1.y=begin_y;
q.push(n1);
vis[n1.x][n1.y]=true; //除门之外所有的点都要进行标记
while(!q.empty())
{
n2=q.front();
q.pop();
if(map[n2.x][n2.y]=='G') return true;
if(map[n2.x][n2.y]>='A'&&map[n2.x][n2.y]<='E')
{
if(k[map[n2.x][n2.y]-'A']==0) map[n2.x][n2.y]='.'; //说明钥匙已经全部找到了
else
{
if(q.empty()) return false;
else
{
q.push(n2); //不进行标记,可以多次走,并且不再从此点进行搜索
continue;
}
}
}
for(int i=0;i<4;i++)
{
n1.x=n2.x+dx[i];
n1.y=n2.y+dy[i];
if(judge(n1.x,n1.y))
{
q.push(n1);
vis[n1.x][n1.y]=true;
}
}
}
return false;
}
int main()
{
while(scanf("%d%d",&m,&n)!=EOF&&m+n)
{
for(int i=0;i<m;i++)
scanf("%s",map[i]);
memset(k,0,sizeof(k)); //用来保存钥匙的数量
for(int i=0;i<m;i++)
for(int j=0;j<n;j++)
{
if(map[i][j]=='S')
{
begin_x=i;
begin_y=j;
}
if(map[i][j]>='a'&&map[i][j]<='e') k[map[i][j]-'a']++;
}
if(bfs()) printf("YES\n");
else printf("NO\n");
}
return 0;
}
附上测试数据
5 5
e.b.S
XXA.E
GX.Xc
C…X
XXXBX
5 5
e.b.S
XXA.E
GX.Xc
C….
XXXBX
5 5
ecb.S
XaX.E
GX.Xc
CA…
XXXcX
5 5
Xae.S
cXX.E
XXXXc
CAA..
GXXcX
5 5
AEe.S
cXX.E
XXXXc
CAA..
GXXcX
5 5
Aae.S
cXX.E
XXXXc
CAAE.
GXXcX
1 2
SG
1 3
SXG
5 5
SXaXG
.X.X.
.X.X.
.X.XA
…..
5 5
aE..S
bXX.c
XX.CX
GBA.B
XXe.e
5 5
a…a
XX.XX
bXSXG
.XAXB
…..
5 5
.X.XG
Sa..A
.b.Xc
XX0
.B
bC…
5 5
.X.XG
Sb..B
.b.Xc
XX..B
bC…
1 10
S.aAbBcC.G
0 0答案
YES
YES
YES
NO
YES
YES
YES
NO
YES
YES
YES
YES
NO
YES