Star night (dfs)

In the depths of the night sky, shining stars appear in people's eyes in the form of clusters of stars, in various forms.

A constellation refers to a group of non-empty stars that are adjacent in the horizontal, vertical or diagonal directions.

A constellation cannot be part of a larger constellation.

The constellations may be similar.

If two constellations have the same shape and number of stars, they are considered similar regardless of their orientation.

Generally, there may be 8 orientations of constellations, as shown in the figure below:

Insert picture description here
Now, we use a two-dimensional 01 matrix to represent the night sky. If the number at a position is 1, then there is a star at this position, otherwise the number at this position should be 0.

Given a two-dimensional matrix of the night sky, please mark all the constellations in it with lowercase letters. When marking similar constellations use the same letter, and dissimilar constellations use different letters.

To label a constellation means to replace all 1s in the constellation with lowercase letters.

Input format

The first line contains an integer W, which represents the width of the matrix.

The second line contains an integer H, which represents the height of the matrix.

In the next H rows, each row contains a 01 sequence of length W, which is used to describe the entire night sky matrix.

Output format

Output the two-dimensional matrix after marking all constellations.

There are many ways to mark constellations with lowercase letters. We read the entire output as a string. The marking method that can make the string lexicographically smallest is the marking method we want.

Output the final two-dimensional matrix marked by this marking method.

data range

0≤W, H≤100,
the number 0≤ constellation ≤500,
0≤ not similar number of constellations ≤26,
the number of stars in the constellation of 1≤ ≤160

Input sample:

23
15
10001000000000010000000
01111100011111000101101
01000000010001000111111
00000000010101000101111
00000111010001000000000
00001001011111000000000
10000001000000000000000
00101000000111110010000
00001000000100010011111
00000001110101010100010
00000100110100010000000
00010001110111110000000
00100001110000000100000
00001000100001000100101
00000001110001000111000

Sample output:

a000a0000000000b0000000
0aaaaa000ccccc000d0dd0d
0a0000000c000c000dddddd
000000000c0b0c000d0dddd
00000eee0c000c000000000
0000e00e0ccccc000000000
b000000e000000000000000
00b0f000000ccccc00a0000
0000f000000c000c00aaaaa
0000000ddd0c0b0c0a000a0
00000b00dd0c000c0000000
000g000ddd0ccccc0000000
00g0000ddd0000000e00000
0000b000d0000f000e00e0b
0000000ddd000f000eee000

The idea of ​​dfs and hash is used

Not only need to record the points of the constellation, but also the shape of the constellation

For points, you can use a variable cnt to record

For the shape, there is a trick to calculate the sum of the distances of any two points in the constellation and then accumulate them. The sum of the distances is unique, namely:

∑ x ∈ D, y ∈ D (x ≠ y) ∣ ∣ x - y ∣ ∣ ∑_ {x∈D, y∈D ~ (x ≠ y)} || xy || xD,yD (x= y )xy

Put all the calculated distances into an array, each time you traverse the array to determine whether the values ​​are equal, and see if the current sum of distances has appeared

And because it is a double type, an eps needs to be added when the judgment is equal

#include <bits/stdc++.h>
using namespace std;
const int N = 105;
#define x first
#define y second

int n, m, cnt; // cnt表示当前连通块的点数
char g[N][N], mark;
bool vis[N][N];
typedef pair<int, int> PII;
PII shape[N * N]; // 记录每个连通块的所有位置
// 计算两点间的距离
double get_dist(PII a, PII b)
{
    
    
    double x = a.x - b.x;
    double y = a.y - b.y;
    return sqrt(x * x + y * y);
}
// 得到距离之和
double get_hash()
{
    
    
    double res = 0;
    for (int i = 0; i < cnt; i++) {
    
    
        for (int j = i + 1; j < cnt; j++) {
    
    
            res += get_dist(shape[i], shape[j]);
        }
    }
    return res;
}
// 得到连通块的标记
char get_id(double v)
{
    
    
    static double hash[N]; // 记录所有连通块的距离
    static int cnt = 0;
    for (int i = 0; i < cnt; i++) {
    
    
        if (fabs(v - hash[i]) < 1e-6) {
    
    
            return 'a' + i;
        }
    }
    hash[cnt++] = v;
    return 'a' + cnt - 1;
}

void dfs(int x, int y)
{
    
    
    // 记录位置
    shape[cnt++] = {
    
    x, y};
    //cout << cnt << endl;
    vis[x][y] = 1;
    for (int dx = -1; dx <= 1; dx++) {
    
    
        for (int dy = -1; dy <= 1; dy++) {
    
    
            int nx = x + dx, ny = y + dy;
            if (nx >= 0 && nx < n && ny >= 0 && ny < m && g[nx][ny] == '1' && vis[nx][ny] == 0) {
    
    
                dfs(nx, ny);
            }
        }
    }
}

int main(void)
{
    
    
    cin >> m >> n;
    for (int i = 0; i < n; i++) {
    
    
        cin >> g[i];
    }
    for (int i = 0; i < n; i++) {
    
    
        for (int j = 0; j < m; j++) {
    
    
            cin >> g[i][j];
            if (g[i][j] == '1') {
    
    
                // 初始化连通块的点数
                cnt = 0;
                dfs(i, j);
                // 得到哈希(距离之和)
                double hash = get_hash();
                // 得到对应的标记
                mark = get_id(hash);
                // 标记连通块
                for (int k = 0; k < cnt; k++) {
    
    
                    g[shape[k].x][shape[k].y] = mark;
                }
            }
        }
    }
    for (int i = 0; i < n; i++) {
    
    
        for (int j = 0; j < m; j++) {
    
    
            cout << g[i][j];
        }
        cout << endl;
    }
    
    return 0;
}

Guess you like

Origin blog.csdn.net/weixin_43772166/article/details/113279217
dfs