NYOJ迷宫寻宝(一)

描述

一个叫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')                 

 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();   //消除回车
}


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++;                                           //队首位置的坐标四个方向尝试完后出队 
}
}

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值