NO
这一题写了一天。。。遍历图其实有两种方法,一种是bfs(宽度优先搜索),另一种dfs(深度优先搜索),像这种图的遍历一般建议用bfs,两种方法具体实现没法跟你讲,自己查资料或浏览以下AC代码。本题的思路是这样的,先从‘S’出发调用bfs,实时判断是否到达‘G’,找到了最好,如果未找到怎么办呢?就是得判断有没有出现过无法通过的门。所以这就需要用数组记录下之前无法通过的门,然后再遍历这些门,如果遇到一些门找到钥匙则以该门为起点继续调用bfs,如此往复。所以这是个好题。代码以注释
AC代码:
/*以下代码在下原创,如有不足多多指正*/ # include <stdio.h> # include <string.h> # include <ctype.h> # include <stdlib.h> # include <queue> using namespace std; queue<int> q; int m, n; int vis[50][50]; int a[200]; int des[200]; char g[50][50]; //这个结构体的作用就是用来记录当时遇到门时,没足够钥匙的门 struct node{ int r; int c; int flage;//先前遇到打不开的门,还未处理时记为1 ,处理后记为零 }; int x[4]={0, 0, 1, -1}; int y[4]={1, -1, 0, 0}; int cnt, Find, Flage; struct node s[410]; //init()函数进行初始化,就是在外围加一圈'X' //这样做感觉便于操作,不用判断边界 void init(){ for(int i=0; i<=n+1; i++){ g[0][i]='X'; } for(int i=1; i<=m; i++){ g[i][0]='X';g[i][n+1]='X'; } for(int i=0; i<=n+1; i++){ g[m+1][i]='X'; } } void bfs(){//宽度优先搜索函数 int r, c, num; while(!q.empty()){ num=q.front(); q.pop(); r=num/n+1; c=num%n; if(c==0){ r--; c=n; } for(int i=0; i<=3; i++){ if(g[r+x[i]][c+y[i]]=='G'){ Find=1;//找到'G' return; } if(!vis[r+x[i]][c+y[i]]){ if(isalpha(g[r+x[i]][c+y[i]])){//g[i][j]为字母 if(g[r+x[i]][c+y[i]]>='a'){//找到一把钥匙 a[g[r+x[i]][c+y[i]]]++;//总数加一 g[r+x[i]][c+y[i]]='.';//化为'.' ,即可行的路 vis[r+x[i]][c+y[i]]=1; q.push((r+x[i]-1)*n+c+y[i]); } else if(g[r+x[i]][c+y[i]]<='E'){//遇到门 if(a[g[r+x[i]][c+y[i]]+32]==des[g[r+x[i]][c+y[i]]+32]){ //如果钥匙数已经够可以开门 g[r+x[i]][c+y[i]]='.'; vis[r+x[i]][c+y[i]]=1; q.push((r+x[i]-1)*n+c+y[i]); } else{ //如果钥匙数还不够,记录一下门的位置 s[cnt].r=r+x[i];s[cnt].c=c+y[i];s[cnt].flage=1; cnt++; } } } else{ vis[r+x[i]][c+y[i]]=1; q.push((r+x[i]-1)*n+c+y[i]); } } } } return; } int main(){ int i, j, k, b_r, b_c, temp1, temp2, no; while(scanf("%d%d", &m, &n)){ getchar(); if(m==0&&n==0){ break; } for(i=1; i<=m; i++){ scanf("%s", g[i]+1); } init(); while(!q.empty()){//队列初始化清空 q.pop(); } memset(vis, 0, sizeof(vis)); memset(a, 0, sizeof(a)); memset(des, 0, sizeof(des)); cnt=0;Find=0;Flage=1; for(i=1; i<=m; i++){ for(j=1; j<=n; j++){ if(g[i][j]=='S'){ b_r=i;b_c=j; } if(isalpha(g[i][j])&&g[i][j]>='a'){ des[g[i][j]]++;//记录门对应的钥匙总数 } } } g[b_r][b_c]='.'; vis[b_r][b_c]=1; no=(b_r-1)*n+b_c; q.push(no); bfs();//从'S'点开始调用bfs while(!Find&&Flage){ //Find!=1时表示还没找到'G'; // Flage==1时表示之前有一个无法通过的门现在找到钥匙 //则以这个门为起点再次调用bfs Flage=0; for(i=0; i<=cnt-1; i++){ temp1=s[i].r;temp2=s[i].c; if(g[temp1][temp2]>='A'&&g[temp1][temp2]<='E'&&s[i].flage&&a[g[temp1][temp2]+32]==des[g[temp1][temp2]+32]){ s[i].flage=0; Flage=1; break; } } if(Flage){ memset(vis, 0, sizeof(vis)); g[temp1][temp2]='.'; vis[temp1][temp2]=1; while(!q.empty()){ q.pop(); } q.push((temp1-1)*n+temp2); bfs(); } } if(Find){//Find==1表示找到 printf("YES\n"); } else{ printf("NO\n"); } } return 0; }