题目地址:
https://www.luogu.com.cn/problem/P1141
题目描述:
有一个仅由数字
0
0
0与
1
1
1组成的
n
×
n
n×n
n×n格迷宫。若你位于一格
0
0
0上,那么你可以移动到相邻
4
4
4格中的某一格
1
1
1上,同样若你位于一格
1
1
1上,那么你可以移动到相邻
4
4
4格中的某一格
0
0
0上。你的任务是:对于给定的迷宫,询问从某一格开始能移动到多少个格子(包含自身)。
输入格式:
第
1
1
1行为两个正整数
n
,
m
n,m
n,m。
下面
n
n
n行,每行
n
n
n个字符,字符只可能是
0
0
0或者
1
1
1,字符之间没有空格。
接下来
m
m
m行,每行
2
2
2个用空格分隔的正整数
i
,
j
i,j
i,j,对应了迷宫中第
i
i
i行第
j
j
j列的一个格子,询问从这一格开始能移动到多少格。
输出格式:
m
m
m行,对于每个询问输出相应答案。
数据范围:
所有格子互相可达。
对于
20
%
20\%
20%的数据,
n
≤
10
n≤10
n≤10;
对于
40
%
40\%
40%的数据,
n
≤
50
n≤50
n≤50;
对于
50
%
50\%
50%的数据,
m
≤
5
m≤5
m≤5;
对于
60
%
60\%
60%的数据,
n
≤
100
,
m
≤
100
n≤100,m≤100
n≤100,m≤100;
对于
100
%
100\%
100%的数据,
n
≤
1000
,
m
≤
100000
n≤1000,m≤100000
n≤1000,m≤100000。
可以用并查集,实际上是求连通块大小的问题。代码如下:
#include <iostream>
#include <cstring>
using namespace std;
const int N = 1e3 + 10;
int d[] = {-1, 0, 1, 0, -1};
int n, m;
char g[N][N];
int p[N * N], sz[N * N];
int get(int x, int y) {
return x * n + y;
}
int find(int x) {
if (p[x] != x) p[x] = find(p[x]);
return p[x];
}
int main() {
scanf("%d%d", &n, &m);
for (int i = 0; i < n; i++)
scanf("%s", g[i]);
for (int i = 0; i < n * n; i++) {
p[i] = i;
sz[i] = 1;
}
for (int i = 0; i < n; i++)
for (int j = 0; j < n; j++)
for (int k = 0; k < 4; k++) {
int ni = i + d[k], nj = j + d[k + 1];
if (0 <= ni && ni < n && 0 <= nj && nj < n && g[i][j] != g[ni][nj]) {
int px = find(get(i, j)), py = find(get(ni, nj));
if (px != py) {
p[px] = py;
sz[py] += sz[px];
}
}
}
while (m--) {
int x, y;
scanf("%d%d", &x, &y);
x--, y--;
printf("%d\n", sz[find(get(x, y))]);
}
return 0;
}
时间复杂度 O ( n 2 log ∗ n 2 ) O(n^2\log ^*n^2) O(n2log∗n2),空间 O ( n 2 ) O(n^2) O(n2)。