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++;                                           //隊首位置的座標四個方向嘗試完後出隊 
}
}

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章