20200820写这一道题(01迷宫)花了整整一个下午,最后在写代码-翻书-思考-看题解-思考-写代码-翻书-思考-看题解-思考这样一个循环下,终于写了出来,激动之余,写篇博客记录下此时的心情以及AC的代码。
题目
题目描述
有一个仅由数字0与1组成的n×n格迷宫。若你位于一格0上,那么你可以移动到相邻4格中的某一格1上,同样若你位于一格1上,那么你可以移动到相邻4格中的某一格0上。
你的任务是:对于给定的迷宫,询问从某一格开始能移动到多少个格子(包含自身)。
输入格式
第1行为两个正整数n,m。
下面n行,每行n个字符,字符只可能是0或者1,字符之间没有空格。
接下来m行,每行2个用空格分隔的正整数i,j,对应了迷宫中第i行第j列的一个格子,询问从这一格开始能移动到多少格。
输出格式
m行,对于每个询问输出相应答案。
输入输出样例
输入
2 2
01
10
1 1
2 2
输出
4
4扫描二维码关注公众号,回复: 11877421 查看本文章
说明/提示
所有格子互相可达。
对于20%的数据,n≤10;
对于40%的数据,n≤50;
对于50%的数据,m≤5;
对于60%的数据,n≤100,m≤100;
对于100%的数据,n≤1000,m≤100000。
首先是BFS解法:
#include<stdio.h>
int n,m,startx,starty,ans;
int a[1005][1005],book[1005][1005];
int next[5][2]={
{
0,0},{
0,1},{
1,0},{
0,-1},{
-1,0}};
int head=1,tail=1;
struct note{
int x; //横坐标
int y; //纵坐标
};
struct note que[1000005];
void bfs(int x,int y)
{
int tx,ty,ans=0;
head=1,tail=1; //初始化
que[tail].x=x; //初始坐标
que[tail].y=y;
book[x][y]=1; //标记走过了
ans++; //审题,自身也算一个
tail++;
while(head<tail){
//当队列不为空时
for(int i=1;i<=4;i++){
//四个方向
tx=que[head].x+next[i][0];
ty=que[head].y+next[i][1];
if(tx<1||tx>n||ty<1||ty>n) continue; //是否越界
//判断是否满足要求和是否以及走过
if(a[que[head].x][que[head].y]!=a[tx][ty]&&book[tx][ty]==0){
que[tail].x=tx; //下一个坐标
que[tail].y=ty;
book[tx][ty]=1; //标记
ans++; // 可以走,答案加1
tail++;
}
}
head++;
}
for(int i=1;i<tail;i++){
book[que[i].x][que[i].y]=ans; // 同一个连通块的答案都一样,反反复复可以走
}
}
int main()
{
scanf("%d%d",&n,&m);
for(int i=1;i<=n;i++){
for(int j=1;j<=n;j++){
scanf("%1d",&a[i][j]); //储存地图
}
}
while(m--){
//m个循环
scanf("%d%d",&startx,&starty); //初始坐标
if(book[startx][starty]) printf("%d\n",book[startx][starty]); //如果这个坐标标记过,即走过了,就直接输出
else{
bfs(startx,starty);//如果这个坐标没有走过,那么就搜索
printf("%d\n",book[startx][starty]); //然后输出
}
}
return 0;
}
接下来是DFS解法
#include<stdio.h>
int n,m,ans[100002],sx,sy,book[1002][1002]; //ans用来存储答案,book用来标记
int a[1002][1002]; //a用来存储地图
int next[5][2]={
{
0,0},{
0,1},{
1,0},{
0,-1},{
-1,0}};//四个方向
void dfs(int x,int y,int z,int t){
int tx,ty;
book[x][y]=t; //标记连通块
ans[t]++; //自身算一个,所以要加1
for(int i=1;i<=4;i++){
tx=x+next[i][0]; //四个方向的坐标
ty=y+next[i][1];
if (tx<1 || ty>n || ty<1 || tx>n ) continue; //放在越界
if(book[tx][ty]==0&&a[tx][ty]!=z){
//判断是否已经走过和是否满足要求
dfs(tx,ty,!z,t); //!z可以改为a[tx][ty]
}
}
}
int main()
{
scanf("%d%d",&n,&m);
for (int i=1;i<=n;i++){
for(int j=1;j<=n;j++){
scanf("%1d",&a[i][j]); //存储地图
}
}
for (int i=1;i<=m;i++)
{
scanf("%d%d",&sx,&sy); //起始坐标
if (book[sx][sy]==0) {
//如果这个坐标还没有走过
dfs(sx,sy,a[sx][sy],i); //则搜索遍历
}
else{
ans[i]=ans[book[sx][sy]]; //反之输出
}
}
for (int i=1;i<=m;i++)
printf("%d\n",ans[i]);
return 0;
}
这就是写了整整一个下午的题目,一开始思路都没有,接着有思路了,但是超时了三个,后来看提示说明才知道数据很大(这也给了我们一个启发,如果参加蓝桥杯、CCF等比赛时,不要过了样例马上就去提交哦,要看题目给的提示以及检查自己写的代码是否跟思路一致了),如果每输入一个起始坐标就重新搜一次肯定会超时。优化代码优化了一段时间还是超时三个,接着看题解慢慢得就发觉这是连通块+着色标记法,还好前一天有学习到,理解起来就没有那么困难!!!也有的同学是用并查集做的,但是本萌新还没有学到,就没有去了解。及时总结,复习,不然第二天还是会忘记的!!!挑战自己,让自己难起来,加油!!