题目描述

有一个仅由数字0与1组成的n×n格迷宫。若你位于一格0上,那么你可以移动到相邻4格中的某一格1上,同样若你位于一格1上,那么你可以移动到相邻4格中的某一格0上。
你的任务是:对于给定的迷宫,询问从某一格开始能移动到多少个格子(包含自身)。

输入输出格式

输入格式:
输入的第1行为两个正整数n,m。
下面n行,每行n个字符,字符只可能是0或者1,字符之间没有空格。
接下来m行,每行2个用空格分隔的正整数i,j,对应了迷宫中第i行第j列的一个格子,询问从这一格开始能移动到多少格。

输出格式:
输出包括m行,对于每个询问输出相应答案。

输入输出样例

输入样例#1:
2 2
01
10
1 1
2 2

输出样例#1:
4
4

说明
所有格子互相可达。
对于20%的数据,n≤10;
对于40%的数据,n≤50;
对于50%的数据,m≤5;
对于60%的数据,n≤100,m≤100;
对于100%的数据,n≤1000,m≤100000。
.
.
.
.
.
.
.

分析

由于每次只向四个方向尝试移动,所以可采用深搜。
然而数据规模中,n<=1000,m<=100000,如果每次输入坐标时重新走一次将会超时。
再想想,每一次搜索会找到一个区块,该区块中所有点的答案都相同,所以,答案可以存在一个数组里

题目每给出一个坐标,先判断该坐标是否已有答案(通过前面已给出的点搜索获得的),是则直接输出,否则深搜:先重置pl,为了将该点所属区块都染上色(不能在深搜内部染色,因为过程中并不知道区域内到底有多少连通点),在一趟深搜过程中,每到一个新的点就pl+1,并将该点的坐标存在临时数组里,搜索结束后再依据坐标数组把答案数组的对应位置填上pl。
.
.
.
.
.
.
.
.

程序:
const
x1:array[1..4]of longint=(1,-1,0,0);
y1:array[1..4]of longint=(0,0,1,-1);
var
a,ans:array[0..1001,0..1001]of longint;
x,y:array[0..1000001]of longint;
n,m,pl,i,j:longint;
ch:char;

procedure dfs(p,q:longint);
var
i,u,v:longint;
begin
    inc(pl);
    x[pl]:=p;
    y[pl]:=q;
    ans[p,q]:=1;
    for i:=1 to 4 do
    begin
        u:=p+x1[i];
        v:=q+y1[i];
        if (u<1)or(u>n)or(v<1)or(v>n) then continue;
        if (ans[u,v]>0) then continue;
        if (a[u,v]=a[p,q]) then continue;
        dfs(u,v);
    end;
end;

begin
    fillchar(ans,sizeof(ans),0);
    readln(n,m);
    for i:=1 to n do
    begin
        for j:=1 to n do
        begin
            read(ch);
            a[i,j]:=ord(ch)-ord('0');
        end;
        readln;
    end;
    for i:=1 to m do
    begin
        pl:=0;
        readln(x[i],y[i]);
        if ans[x[i],y[i]]>0 then
        begin
            writeln(ans[x[i],y[i]]);
            continue;
        end;
        dfs(x[i],y[i]);
        for j:=1 to pl do
        ans[x[j],y[j]]:=pl;
        writeln(pl);
    end;
end.