题目描述
有一个仅由数字 00 与 11 组成的 n \times nn×n 格迷宫。若你位于一格0上,那么你可以移动到相邻 44 格中的某一格 11 上,同样若你位于一格1上,那么你可以移动到相邻 44 格中的某一格 00 上。
你的任务是:对于给定的迷宫,询问从某一格开始能移动到多少个格子(包含自身)。
输入输出格式
输入格式:第 11 行为两个正整数 n,mn,m 。
下面 nn 行,每行 nn 个字符,字符只可能是 00 或者 11 ,字符之间没有空格。
接下来 mm 行,每行 22 个用空格分隔的正整数 i,ji,j ,对应了迷宫中第 ii 行第 jj 列的一个格子,询问从这一格开始能移动到多少格。
输出格式:mm 行,对于每个询问输出相应答案。
输入输出样例
2 2 01 10 1 1 2 2
4 4
说明:
所有格子互相可达。
对于 20\%20% 的数据, n≤10n≤10 ;
对于 40\%40% 的数据, n≤50n≤50 ;
对于 50\%50% 的数据, m≤5m≤5 ;
对于 60\%60% 的数据, n≤100,m≤100n≤100,m≤100 ;
对于 100\%100% 的数据, n≤1000,m≤100000
n≤1000,m≤100000
思路:
这是一道广搜题,但我更倾向于用深搜来做。一看题目,很容易就可以想到,对输入的询问点进行深搜,深搜的条件是当前点和下一个点的值不一样(0和1)。但是,看这题m的值,m<=100000,所以如果老老实实进行模拟,时间肯定会爆炸。所以应该使用记忆式搜索。其实如果若干个点之间可以互相同行,那么这几个点的答案是相同的,这里不多解释。所以在输入后立即对地图上每个点进行搜索(此时每个点可以看成独立的)。当每一次搜索结束,就把这一整个块内的所有点联系到一起(即用一个father数组表示他们是之间的答案是一样的,可以形象地理解为是一个“家族”)。然后用另一个result数组(栈)表示一个家族的答案。问题解决。
代码:
#include<cstdio>
#include<iostream>
#include<queue>
using namespace std;
int m,n,count;
char map[2001][2001];
int father[2001][2001];
bool b[2001][2001];
int result[10000005];
int head=0;
void bfs(int,int);
int main()
{
scanf("%d %d",&n,&m);
for(int i=1;i<=n;i++)
for(int j=1;j<=n;j++)
{
cin>>map[i][j];
b[i][j]=true;
}
for(int i=1;i<=n;i++)
for(int j=1;j<=n;j++)
{
if(b[i][j])
{
head++;
count=1;
bfs(i,j);
result[head]=count;
}
}
int a,b;
for(int i=1;i<=m;i++)
{
cin>>a>>b;
cout<<result[father[a][b]]<<endl;
}
return 0;
}
void bfs(int x,int y)
{
b[x][y]=false;
father[x][y]=head;
if(b[x+1][y]&&map[x][y]!=map[x+1][y])
{
count++;
bfs(x+1,y);
}
if(b[x][y+1]&&map[x][y]!=map[x][y+1])
{
count++;
bfs(x,y+1);
}
if(b[x-1][y]&&map[x][y]!=map[x-1][y])
{
count++;
bfs(x-1,y);
}
if(b[x][y-1]&&map[x][y]!=map[x][y-1])
{
count++;
bfs(x,y-1);
}
}