洛谷 P10379 [GESP202403 七级] 俄罗斯方块-普及/提高-

题目描述

小杨同学用不同种类的俄罗斯方块填满了一个大小为 n × m n \times m n×m 的网格图。

网格图由 n × m n \times m n×m 个带颜色方块构成。小杨同学现在将这个网格图交给了你,请你计算出网格图中俄罗斯方块的种类数。

如果两个同色方块是四连通(即上下左右四个相邻的位置)的,则称两个同色方块直接连通;若两个同色方块同时与另一个同色方块直接或间接连通,则称两个同色方块间接连通。一个俄罗斯方块由一个方块和所有与其直接或间接连接的同色方块组成。定义两个俄罗斯方块的种类相同当且仅当通过平移其中一个俄罗斯方块可以和另一个俄罗斯方块重合;如果两个俄罗斯方块颜色不同,仍然视为同一种俄罗斯方块。

例如,在如下情况中,方块 1 1 1 和方块 2 2 2 是同一种俄罗斯方块,而方块 1 1 1 和方块 3 3 3 不是同一种俄罗斯方块。

输入格式

第一行包含两个正整数 n n n 和 m m m,表示网格图的大小。

对于之后的 n n n 行,第 i i i 行包含 m m m 个正整数 a i 1 , a i 2 , ... a i m a_{i1}, a_{i2}, \dots a_{im} ai1,ai2,...aim,表示该行 m m m 个方块的颜色。

输出格式

输出一行一个整数表示答案。

输入输出样例 #1

输入 #1

复制代码
5 6
1 2 3 4 4 5
1 2 3 3 4 5
1 2 2 3 4 5
1 6 6 7 7 8
6 6 7 7 8 8

输出 #1

复制代码
7

说明/提示

子任务 分数 n , m ≤ n,m \leq n,m≤ 特殊约定
1 1 1 30 30 30 20 20 20 所有俄罗斯方块大小不超过 5 × 5 5 \times 5 5×5
2 2 2 30 30 30 500 500 500 所有俄罗斯方块大小均为 1 × x 1 \times x 1×x 或 x × 1 x \times 1 x×1 类型,其中 x x x 是任意正整数
3 3 3 40 40 40 500 500 500

对全部的测试数据,保证 1 ≤ n , m ≤ 500 1 \leq n, m \leq 500 1≤n,m≤500, 1 ≤ a i , j ≤ n × m 1 \leq a_{i,j} \leq n \times m 1≤ai,j≤n×m。

solution

这道题本质是每一个小整体的中各小方块的相对位置是否相同,如果用固定的搜索顺序的话,每一个方块的搜索方向决定了相对位置。所以可以用搜索方向的方向序列表示唯一表示一种俄罗斯方块。但是需要注意的是,深度优先搜索过程中,某一个位置搜索完成后会回到上一层继续搜索,此时就会出现有可能的不唯一表示,比方说

序列1: 在 A 点处,向下搜索

序列2: 在 A 点处,递归结束,回到 B 点, B 点向下搜索。

可以在每一个点递归结束后添加一个标记即可。

代码

cpp 复制代码
#include <iostream>
#include "bit"
#include "vector"
#include "unordered_set"
#include "set"
#include "queue"
#include "stack"
#include "algorithm"
#include "bitset"
#include "cstring"

using namespace std;

int col, sx, sy, m, n, mat[501][501];
int dx[] = {1, -1, 0, 0};
int dy[] = {0, 0, 1, -1};
bool vis[501][501];
string s;

void dfs(int x, int y) {
    vis[x][y] = true;
    for (int i = 0; i < 4; i++) {
        int xx = x + dx[i];
        int yy = y + dy[i];
        if (xx >= 0 && x < m && yy >= 0 && yy < n && !vis[xx][yy] && mat[xx][yy] == col) {
            s.push_back(char(i + '0'));
            dfs(xx, yy);
        }
    }
    s.push_back('x');
}

int main() {
    cin >> m >> n;
    for (int i = 0; i < m; i++) {
        for (int j = 0; j < n; j++) {
            cin >> mat[i][j];
        }
    }

    unordered_set<string> set;
    for (int i = 0; i < m; i++) {
        for (int j = 0; j < n; j++) {
            if (!vis[i][j]) {
                col = mat[i][j];
                s.clear();
                dfs(i, j);
                set.insert(s);
            }
        }
    }
    cout << set.size();
}

结果