一个叫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找不到宝藏。
深搜法
#include<stdio.h>
#include<string.h>
void fun(int,int);
char arr[25][25];int arr1[25][25],flag,m,n;
int a,b,c,d,e,a1,b1,c1,d1,e1;
int main()
{
int i,j,m1,n1;
while(1)
{
memset(arr1,0,sizeof(arr1));
scanf("%d%d",&m,&n);
if(m==0&&n==0)
break;
a=b=c=d=e=0;
a1=b1=c1=d1=e1=0;
flag=0;
getchar(); //消除回车
for(i=0;i<m;i++)
{
for(j=0;j<n;j++)
{
scanf("%c",&arr[i][j]);
//统计每种钥匙的数量
if(arr[i][j]=='a')
else if(arr[i][j]=='b')
b1++;
else if(arr[i][j]=='c')
c1++;
else if(arr[i][j]=='d')
d1++;
else if(arr[i][j]=='e')
e1++;
else if(arr[i][j]=='S')
{
m1=i;
n1=j;
}
}
getchar(); //消除回车
}
fun(m1,n1);
if(flag==1)
printf("YES\n");
else
printf("NO\n");
}
return 0;
}
void fun(int x,int y)
{
if(arr[x][y]=='G') //递归出口
{
flag=1; //用于剪枝操作
return ;
}
int tx,ty;
//定义四个方向坐标 下 左 上 右
int next[4][2]={{1,0},{0,-1},{-1,0},{0,1}};for(int i=0;i<4;i++)
{
//向四个方向尝试
tx=x+next[i][0];ty=y+next[i][1];
//判断是否越界,是否有墙,是否走过
if(tx<0||tx>=m||ty<0||ty>=n||arr[tx][ty]=='X'||arr1[tx][ty]==1)continue;
//遇到门的时候判断是否能打开门,若不能打开当作墙
若能打开则当作路
if(arr[tx][ty]=='A'&&a<a1){
continue;
}
else if(arr[tx][ty]=='B'&&b<b1)
{
continue;
}
else if(arr[tx][ty]=='C'&&c<c1)
{
continue;
}
else if(arr[tx][ty]=='D'&&d<d1)
{
continue;
}
else if(arr[tx][ty]=='E'&&e<e1)
{
continue;
}
// 遇到钥匙把钥匙拿走,并且把钥匙变为路
else if(arr[tx][ty]=='a'){
a++;
arr[tx][ty]='.';
}
else if(arr[tx][ty]=='b')
{
b++;
arr[tx][ty]='.';
}
else if(arr[tx][ty]=='c')
{
c++;
arr[tx][ty]='.';
}
else if(arr[tx][ty]=='d')
{
d++;
arr[tx][ty]='.';
}
else if(arr[tx][ty]=='e')
{
e++;
arr[tx][ty]='.';
}
//走过的坐标进行标记
arr1[tx][ty]=1;
//进行下一次尝试
fun(tx,ty);
//若flag=1,说明已经找到宝藏,则直接返回,不用进行其他尝试
即剪枝操作,提高效率
if(flag==1)return;
//取消标记
arr1[tx][ty]=0;}
}
广搜法
#include<stdio.h>
#include<string.h>
char arr[30][30];
int arr1[30][30],a,a1,b,b1,c,c1,d,d1,e,e1;
int m,n,flag;
int judge();
void dfs(int,int);
struct node
{
int x,y;
} s[500];
int main()
{
int i,j,m1,n1;
while(1)
{
scanf("%d%d",&m,&n);
if(m==0&&n==0)
break;
flag=0;
a=b=c=d=e=a1=b1=c1=d1=e1=0;
memset(arr1,0,sizeof(arr1));
getchar();
for(i=0;i<m;i++)
{
for(j=0;j<n;j++)
{
scanf("%c",&arr[i][j]);
//统计各种钥匙的数量
if(arr[i][j]=='a')
a1++;
else if(arr[i][j]=='b')
b1++;
else if(arr[i][j]=='c')
c1++;
else if(arr[i][j]=='d')
d1++;
else if(arr[i][j]=='e')
e1++;
else if(arr[i][j]=='S')
{
m1=i;
n1=j;
}
}
getchar();
}
dfs(m1,n1);
while(judge()==0&&flag==0) //所有可以去的地方遍历一遍后判断是否有可以打开的门
{
arr[s[0].x][s[0].y]='.'; //如果有可以打开的门,把门变为路,从门的位置继续搜索
dfs(s[0].x,s[0].y);
}
if(flag==1)
{
printf("YES\n");
}
if(flag==0)
{
printf("NO\n");
}
}
return 0;
}
// 判断是否有能到达且能打开的门
int judge()
{
int i,j;
if(a>=a1&&a1!=0)
{
for(i=0;i<m;i++)
{
for(j=0;j<n;j++)
{
//判断能否打开此门且能否到达此门
if(arr[i][j]=='A'&&(arr1[i-1][j]==1||arr1[i+1][j]==1||arr1[i][j+1]==1||arr1[i][j-1]==1))
{
s[0].x=i;
s[0].y=j;
return 0;
}
}
}
}
if(b>=b1&&b1!=0)
{
for(i=0;i<m;i++)
{
for(j=0;j<n;j++)
{
if(arr[i][j]=='B'&&(arr1[i-1][j]==1||arr1[i+1][j]==1||arr1[i][j+1]==1||arr1[i][j-1]==1))
{
s[0].x=i;
s[0].y=j;
return 0;
}
}
}
}
if(c>=c1&&c1!=0)
{
for(i=0;i<m;i++)
{
for(j=0;j<n;j++)
{
if(arr[i][j]=='C'&&(arr1[i-1][j]==1||arr1[i+1][j]==1||arr1[i][j+1]==1||arr1[i][j-1]==1))
{
s[0].x=i;
s[0].y=j;
return 0;
}
}
}
}
if(d>=d1&&d1!=0)
{
for(i=0;i<m;i++)
{
for(j=0;j<n;j++)
{
if(arr[i][j]=='D'&&(arr1[i-1][j]==1||arr1[i+1][j]==1||arr1[i][j+1]==1||arr1[i][j-1]==1))
{
s[0].x=i;
s[0].y=j;
return 0;
}
}
}
}
if(e>=e1&&e1!=0)
{
for(i=0;i<m;i++)
{
for(j=0;j<n;j++)
{
if(arr[i][j]=='E'&&(arr1[i-1][j]==1||arr1[i+1][j]==1||arr1[i][j+1]==1||arr1[i][j-1]==1))
{
s[0].x=i;
s[0].y=j;
return 0;
}
}
}
}
return 1;
}
void dfs(int px,int py)
{
//定义方向数组 下 左 上 右
int next[4][2]={{1,0},{0,-1},{-1,0},{0,1}},i,j;
int end=1,head=1,tx,ty; //head和end分别为队列头和尾
s[end].x=px; //当前位置入队列
s[end].y=py;
arr1[px][py]=1; //对走过的地方标记
end++; //end始终指向队尾
while(end>head)
{
for(i=0;i<4;i++)
{
// 向四个方向分别尝试
tx=s[head].x+next[i][0];
ty=s[head].y+next[i][1];
//判断是否越界,是否有墙,是否走过
if(tx<0||tx>=m||ty<0||ty>=n||arr[tx][ty]=='X'||arr1[tx][ty]==1)
continue;
//判断是否有打不开的门
if(arr[tx][ty]=='A'&&a<a1)
{
continue;
}
else if(arr[tx][ty]=='B'&&b<b1)
{
continue;
}
else if(arr[tx][ty]=='C'&&c<c1)
{
continue;
}
else if(arr[tx][ty]=='D'&&d<d1)
{
continue;
}
else if(arr[tx][ty]=='E'&&e<e1)
{
continue;
}
//遇到钥匙时收集钥匙,并把钥匙的位置初始化为路
else if(arr[tx][ty]=='a')
{
a++;
arr[tx][ty]='.';
}
else if(arr[tx][ty]=='b')
{
b++;
arr[tx][ty]='.';
}
else if(arr[tx][ty]=='c')
{
c++;
arr[tx][ty]='.';
}
else if(arr[tx][ty]=='d')
{
d++;
arr[tx][ty]='.';
}
else if(arr[tx][ty]=='e')
{
e++;
arr[tx][ty]='.';
}
//遇到宝藏返回
if(arr[tx][ty]=='G')
{
flag=1;
return;
}
//满足条件的位置入队列,并进行标记
s[end].x=tx;
s[end].y=ty;
arr1[tx][ty]=1;
end++;
}
head++; //队首位置的坐标四个方向尝试完后出队
}
}