一、题目
题目描述
有一个仅由数字 0 与 1 组成的 n x n 格迷宫。若你位于一格 0 上,那么你可以移动到相邻 4 格中的某一格 1上,同样若你位于一格 1 上,那么你可以移动到相邻 4 格中的某一格 0 上。
你的任务是:对于给定的迷宫,询问从某一格开始能移动到多少个格子(包含自身)。
输入格式
有一个仅由数字 0 与 1 组成的 n x n 格迷宫。若你位于一格 0 上,那么你可以移动到相邻 4 格中的某一格 1 上,同样若你位于一格 1 上,那么你可以移动到相邻 4 格中的某一格 0 上。
你的任务是:对于给定的迷宫,询问从某一格开始能移动到多少个格子(包含自身)。
输出格式
m 行,对于每个询问输出相应答案。
样例 #1
样例输入 #1
2 2
01
10
1 1
2 2
样例输出 #1
4
4
提示
所有格子互相可达。
对于 20% 的数据,n ≤ 10;
对于 40% 的数据,n ≤ 50;
对于 50% 的数据,m ≤ 5;
对于 60% 的数据,n,m ≤ 100;
对于 100% 的数据,n ≤ 1000,m ≤ 100000。
二、思路
起初使用广搜基操来做,对每一个查询的点执行一次广搜,可以得到70分,有三个点会超时。
结合我少有的编程知识,我绞尽脑汁突然发现这个题本质上还是广搜发现联通块。
于是我码某人考虑结合“打表”思路,对二维数组进行联通块发现的预处理,对同一连通块内的所有点记录该连通块内的点数,而后直接输出所要求查询的点的点数。
三、代码
#include<bits/stdc++.h>
using namespace std;
int a[1010][1010],vis[1010][1010],n,ds[1010][1010];
int aa[4]={-1,1,0,0};
int bb[4]={0,0,-1,1};
struct node{
int x;
int y;
};
void bfs(int x,int y){
//广搜板子+遍历过的点放到额外的p队列,以便完成广搜后记录点数
queue<node> q,p;
node f,e;
f={x,y};
q.push(f);
p.push(f);
vis[x][y]=1;
int t=1;
while(!q.empty()){
f=q.front();
q.pop();
for(int i=0;i<4;i++){
int dx=f.x+aa[i];
int dy=f.y+bb[i];
if(dx>0&&dx<=n&&dy>0&&dy<=n&&vis[dx][dy]==0&&a[f.x][f.y]!=a[dx][dy]){
node s={dx,dy};
q.push(s);
p.push(s);
vis[dx][dy]=1;
t++;
}
}
}
//将此联通区域内所遍历的点记录区域点数
while(!p.empty()){
e=p.front();
ds[e.x][e.y]=t;
p.pop();
}
return ;
}
int main(){
int m;
cin>>n>>m;
char c;
for(int i=1;i<=n;i++){
for(int j=1;j<=n;j++){
cin>>c;
a[i][j]=c-48;
ds[i][j]=1;
}
}
//发现所有联通区域 ,建表
for(int i=1;i<=n;i++){
for(int j=1;j<=n;j++){
if(ds[i][j]==1){
bfs(i,j);
}
}
}
//输出结果打表查询
int x,y;
for(int i=1;i<=m;i++){
cin>>x>>y;
cout<<ds[x][y]<<endl;
}
return 0;
}