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