洛谷 P1141 01迷宫 题解

题目描述

有一个仅由数字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。


这道题必须记忆化搜索,要不然只有70分。。。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
#include<cstdio>
#include<cstring>
#include<queue>
using namespace std;
bool array[1001][1001];
bool visited[1001][1001];
int daarray[1001][1001];
int data[1000001];
int n, m;
int dataptr;
int BFS(int x, int y)
{
    if (daarray[x][y] != -1)
        return data[daarray[x][y]];
    queue < int >qx, qy;
    qx.push(x);
    qy.push(y);
    dataptr++;
    int total = 0;
    while (!qx.empty())
    {
        x = qx.front();
        y = qy.front();
        qx.pop();
        qy.pop();
        if (x < 1 || x > n || y < 1 || y > n || visited[x][y])
            continue;
        total++;
        daarray[x][y] = dataptr;
        visited[x][y] = true;
        if (array[x + 1][y] != array[x][y])
        {
            qx.push(x + 1);
            qy.push(y);
        }
        if (array[x - 1][y] != array[x][y])
        {
            qx.push(x - 1);
            qy.push(y);
        }
        if (array[x][y + 1] != array[x][y])
        {
            qx.push(x);
            qy.push(y + 1);
        }
        if (array[x][y - 1] != array[x][y])
        {
            qx.push(x);
            qy.push(y - 1);
        }
    }
    data[dataptr] = total;
    return total;
}


int main()
{
    dataptr = 0;
    memset(daarray, -1, sizeof(daarray));
    scanf("%d%d", &n, &m);
    for (int i = 1; i <= n; i++)
        for (int j = 1; j <= n; j++)
            scanf("%1d", &array[i][j]);
    for (int i = 1; i <= m; i++)
    {
        int x, y;
        int total = 0;
        scanf("%d%d", &x, &y);
        total = BFS(x, y);
        printf("%d\n", total);
    }
}

20180724更新:又做到这题,严格来说并非所谓的记忆化搜索,这里面有一个性质,即只要图中联通块中的点所对应的答案全都是一样的。利用这个性质去做题90分。所以对visited数组的memset清除也就不需要了(删除memset后AC)。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
#include<iostream>
#include<algorithm>
#include<cstring>
#include<string>
#include<vector>
#include<queue>
#include<functional>
using namespace std;
int n, m;
int f[1005][1005];
int varr[1000005], vaptr = 0;
char arr[1005][1005];
bool visited[1005][1005];
int step_x[4] = { 0,0,1,-1 }, step_y[4] = { 1,-1,0,0 };
inline void qpush(int v, int x, int y, queue<int>& qx, queue<int>& qy) {
    if (x>0 && y>0 && x <= n && y <= n && arr[x][y] - '0' == !v && !visited[x][y]) {
        qx.push(x);
        qy.push(y);
    }
}
inline int bfs(int x, int y) {
    if (f[x][y] != -1)return varr[f[x][y]];
    //memset(visited, false, sizeof(visited));
    vaptr++;
    queue<int> qx, qy;
    qx.push(x); qy.push(y);
    int cnter = 0;
    while (!qx.empty()) {
        x = qx.front(); y = qy.front();
        qx.pop(); qy.pop();
        if (visited[x][y])continue;
        f[x][y] = vaptr;
        visited[x][y] = true;
        cnter++;
        for (int i = 0; i<4; i++)qpush(arr[x][y] - '0', x + step_x[i], y + step_y[i], qx, qy);
    }
    return varr[vaptr] = cnter;
}
int main() {
    ios::sync_with_stdio(false);
    memset(f, -1, sizeof(f));
    cin >> n >> m;
    for (int i = 1; i <= n; i++)cin >> arr[i] + 1;
    for (int i = 1; i <= m; i++) {
        int x, y;
        cin >> x >> y;
        cout << bfs(x, y) << endl;
    }
}

发表回复

您的电子邮箱地址不会被公开。 必填项已用 * 标注