题目描述
有一个仅由数字 000 与 111 组成的 n×nn \times nn×n 格迷宫。若你位于一格0上,那么你可以移动到相邻 444 格中的某一格 111 上,同样若你位于一格1上,那么你可以移动到相邻 444 格中的某一格 000 上。
你的任务是:对于给定的迷宫,询问从某一格开始能移动到多少个格子(包含自身)。
输入输出格式
输入格式:
第 111 行为两个正整数 n,mn,mn,m 。
下面 nnn 行,每行 nnn 个字符,字符只可能是 000 或者 111 ,字符之间没有空格。
接下来 mmm 行,每行 222 个用空格分隔的正整数 i,ji,ji,j ,对应了迷宫中第 iii 行第 jjj 列的一个格子,询问从这一格开始能移动到多少格。
输出格式:
mmm 行,对于每个询问输出相应答案。
输入输出样例
输入样例#1: 复制
2 2 01 10 1 1 2 2
输出样例#1: 复制
4 4
说明
所有格子互相可达。
对于 20%20\%20% 的数据, n≤10n≤10n≤10 ;
对于 40%40\%40% 的数据, n≤50n≤50n≤50 ;
对于 50%50\%50% 的数据, m≤5m≤5m≤5 ;
对于 60%60\%60% 的数据, n≤100,m≤100n≤100,m≤100n≤100,m≤100 ;
对于 100%100\%100% 的数据, n≤1000,m≤100000n≤1000,m≤100000n≤1000,m≤100000 。
思路:本题n的范围较小,但是m的范围比较大,所以很明显要用到记忆话搜索(无论DFS或BFS)
仔细观察不难发现,从一个联通快出发,扫描到的所有联通快最终能移动到的格子数与初始联通块一样
所以在一次搜索过后,除了本身赋值外,再把路径的联通块同样赋值,即可达到记忆化的效果.
#include <iostream>
#include <algorithm>
#include <set>
#include <map>
#include <vector>
#include <cstring>
#include <queue>
#define MAXN 100000
using namespace std;
typedef long long ll;
ll n,m,a,b,ma[1005][1005],dx[4]={1,-1,0,0},dy[4]={0,0,1,-1}; //ma记录最终结果 dx dy为方向数组
bool flag[1005][1005]; //标记数组
char arr[1005][1005]; //图
struct Why //队列结构体
{
int x,y;
Why(ll x1,ll y1)
{
x=x1;
y=y1;
}
};
struct W
{
int x,y; //记录路径
};
ll bfs()
{
for(int i = 1; i <= n; i++)
for(int j = 1; j <= n; j++) //遍历每一个点
{
if(ma[ i ][ j ] == 0) //检测之前有没有背扫描过
{
W jl[1000005]; //记录数组一定要开大!不然会WA
jl[0].x=i; //将本身存入路径中
jl[0].y=j;
flag[i][j]=1; //本身已经扫描过
ll ans=1,tt=1; //ans为一次扫描过后的格子数,tt为路径数
queue<Why>A; //结构体队列
A.push(Why(i,j)); //将自己压入队列
while(!A.empty())
{
Why temp = A.front(); //取队首
for(int k = 0; k < 4; k++) //每个方向
{
int tx = temp.x + dx[k], ty = temp.y + dy[k];
if(arr[ temp.x ][ temp.y ] != arr[ tx ][ ty ] && flag[ tx ][ ty ] == 0 && tx >= 1 && tx <= n && ty >= 1 && ty <= n) //如果与本身不相同并且没有扫描过且没有越界
{
flag[ tx ][ ty ] = 1; //标记
ans++; //格子数+1
jl[ tt ].x = tx; //记录路径
jl[ tt ].y = ty;
tt++;
A.push(Why(tx,ty)); //压队
}
}
A.pop(); //弹出队首
}
for(int k = 0; k < tt; k++)
{
ma[ jl[k].x ][ jl[k].y ] = ans; //将路径赋值
}
}
}
return 0;
}
int main()
{
ios::sync_with_stdio(false);
cin>>n>>m;
for(int i = 1; i <= n; i++)
for(int j = 1; j <= n; j++)
cin>>arr[i][j];
bfs();
while(m--)
{
cin>>a>>b;
cout<<ma[a][b]<<endl; //直接输出即可,节省了很大的时间
}
return 0;
}