题目来源 : http://acm.hunnu.edu.cn/online/?action=problem&type=show&id=11082
广度搜索bfs
最后输出的不为“#”的部分,实际上是指1、(点击处若为0)处于此处八个方向内且为0(相当于一个“感染区”)并且这个“感染区”的八个方向除了是0的情况,就必须被不为0且不为地雷的包围)。所以,从点击点开始宽度搜索它的八个方向,若其中某方向地雷数为0,则将此处的x、y压入队列,并标记此处已被访问,此处因为判断为0后,vis[x][y]会由-1更新为find(x,y),所以,当需要判断此处是否被访问过,只要查找vis[x][y]的值是否为-1即可。又由于输出中不为0且不为“#”的vis[x][y]是包围着0的(即它的八个方向中一定有0的存在,且在包围内),所以更新不为0的vis[x][y]的条件就是:have_0() 八个方向是否有0存在。
另外,需要注意的是,边界情况,所以当判断have_0()时,一定要限制x>=1&&x<=16&&y>=1&&y<=30;
代码:
#include<iostream>
#include<string.h>
using namespace std;
char map[50][50];
int vis[50][50];
int dir[8][2]={-1,-1,-1,0,-1,1,0,-1,0,1,1,-1,1,0,1,1};
typedef struct
{
int x,y;
}D;
D quee[10000];
int have_0(int x,int y)
{
int flag=0;
for(int i=0;i<8;i++)
{
int a=x+dir[i][0];
int b=y+dir[i][1];
if(vis[a][b]==0&&a>=1&&a<=16&&b>=1&&b<=30) {flag=1;return 1;}
}
if(flag==0) return 0;
}
int find(int x,int y)
{
int num=0;
if(map[x-1][y-1]=='*') num++;
if(map[x-1][y]=='*') num++;
if(map[x-1][y+1]=='*') num++;
if(map[x][y-1]=='*') num++;
if(map[x][y+1]=='*') num++;
if(map[x+1][y-1]=='*') num++;
if(map[x+1][y]=='*') num++;
if(map[x+1][y+1]=='*') num++;
return num;
}
void bfs(int x,int y)
{
int front,rear;
front=rear=0;
quee[rear].x=x;quee[rear++].y=y;
vis[x][y]=find(x,y);
int nx,ny;
while(front<=rear)
{
nx=quee[front].x;
ny=quee[front++].y;
for(int i=0;i<8;i++)
{
int a,b;
a=nx+dir[i][0];b= ny+dir[i][1];
if(have_0(a,b)==1&&map[a][b]!='*'&&vis[a][b]==-1&&a>=1&&a<=16&&b>=1&&b<=30)
{
vis[a][b]=find(a,b);
if(find(a,b)==0) {quee[rear].x=a;quee[rear++].y=b;}
}
}
}
}
int main()
{
int t;
int x,y;
char str[50];
scanf("%d",&t);
while(t--)
{
scanf("%d%d",&x,&y);
for(int i=0;i<=17;i++)
for(int j=0;j<=31;j++) vis[i][j]=-1;
for(int i=1;i<=16;i++)
{
scanf("%s",str);
for(int j=1;j<=30;j++)
{map[i][j]=str[j-1]; }
}
bfs(x,y);
for(int i=1;i<=16;i++)
{
for(int j=1;j<=30;j++)
{
if(vis[i][j]!=-1) printf("%d",vis[i][j]);
else printf("#");
// cout<<vis[i][j];
}
printf("\n");
}
if(t!=0) printf("\n");
}
return 0;
}