夜空の奥深くに、輝く星が星団の形でさまざまな形で人々の目に現れます。
星座とは、水平方向、垂直方向、または対角線方向に隣接する空でない星のグループを指します。
コンステレーションをより大きなコンステレーションの一部にすることはできません。
星座は似ているかもしれません。
2つの星座の形と星の数が同じである場合、それらは向きに関係なく類似していると見なされます。
次の図に示すように、一般に、星座には8つの方向があります。
ここで、2次元の01行列を使用して夜空を表します。ある位置の数が1の場合、この位置に星があります。それ以外の場合、この位置の数は0になります。
夜空の2次元マトリックスを前提として、その中のすべての星座を小文字でマークしてください。類似した星座をマークする場合は同じ文字を使用し、異なる星座は異なる文字を使用します。
コンステレーションにラベルを付けるとは、コンステレーション内のすべての1を小文字に置き換えることを意味します。
入力フォーマット
最初の行には、行列の幅を表す整数Wが含まれています。
2行目には、行列の高さを表す整数Hが含まれています。
次のH行では、各行に長さWの01シーケンスが含まれています。これは、夜空マトリックス全体を記述するために使用されます。
出力フォーマット
すべてのコンスタレーションをマークした後、2次元行列を出力します。
星座を小文字でマークする方法はたくさんあります。出力全体を文字列として読み取ります。文字列を辞書式に最小化できるマーク方法は、必要なマーク方法です。
このマーキング方法でマーキングされた最終的な2次元行列を出力します。
データ範囲
0≤W、H≤100、
数0≤星座≤500、0≤
類似していない星座
の数≤26、星座内の星の数1≤≤160
入力サンプル:
23
15
10001000000000010000000
01111100011111000101101
01000000010001000111111
00000000010101000101111
00000111010001000000000
00001001011111000000000
10000001000000000000000
00101000000111110010000
00001000000100010011111
00000001110101010100010
00000100110100010000000
00010001110111110000000
00100001110000000100000
00001000100001000100101
00000001110001000111000
サンプル出力:
a000a0000000000b0000000
0aaaaa000ccccc000d0dd0d
0a0000000c000c000dddddd
000000000c0b0c000d0dddd
00000eee0c000c000000000
0000e00e0ccccc000000000
b000000e000000000000000
00b0f000000ccccc00a0000
0000f000000c000c00aaaaa
0000000ddd0c0b0c0a000a0
00000b00dd0c000c0000000
000g000ddd0ccccc0000000
00g0000ddd0000000e00000
0000b000d0000f000e00e0b
0000000ddd000f000eee000
dfsとハッシュのアイデアが使用されます
星座のポイントだけでなく、星座の形も記録する必要があります
ポイントの場合、変数cntを使用して記録できます
形状については、星座内の任意の2点の距離の合計を計算し、それらを累積するトリックがあります。距離の合計は一意です。つまり、次のようになります。
∑x∈D、y∈D(x≠y)∣ ∣ x --y ∣ ∣ ∑_ {x∈D、y∈D〜(x≠y)} || xy || X ∈ D 、Y ∈ D (X = y )Σ| | X−y ∣ ∣
計算されたすべての距離を配列に入れ、配列をトラバースするたびに、値が等しいかどうかを判断し、現在の距離の合計が表示されているかどうかを確認します
また、ダブルタイプですので、判断が等しい場合はepsを追加する必要があります
#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;
}