Acwing 1402. 星空之夜 连通块哈希
程序员文章站
2022-07-12 22:54:08
...
Acwing 1402. 星空之夜
题意
给一个二维01矩阵,寻找连通块,相似的连通块用同一个字母表示,可以通过旋转、对称得到的就是相似。要求输出的矩阵字典序最小。
题解
- dfs搜索即可
- 哈希方式:计算每两个点的欧几里得距离之和,就是这个连通图的哈希值。相似的图形哈希值一定相同,大部分情况下是哈希值不会重复。
代码
#pragma region
//#pragma optimize("Ofast")
#include <algorithm>
#include <cmath>
#include <cstdio>
#include <cstring>
#include <iostream>
#include <map>
#include <queue>
#include <set>
#include <vector>
using namespace std;
typedef long long ll;
#define tr t[root]
#define lson t[root << 1]
#define rson t[root << 1 | 1]
#define rep(i, a, n) for (int i = a; i <= n; ++i)
#define per(i, a, n) for (int i = n; i >= a; --i)
#pragma endregion
const int maxn = 105;
int n, m;
char s[maxn][maxn];
int dir[8][2] = {{0, 1}, {-1, 1}, {-1, 0}, {-1, -1}, {0, -1}, {1, -1}, {1, 0}, {1, 1}};
bool vis[maxn][maxn];
bool check(int x, int y) { return x >= 1 && x <= n && y >= 1 && y <= m && s[x][y] == '1' && !vis[x][y]; }
vector<pair<int, int>> v;
void dfs(int x, int y) {
v.push_back({x, y}), vis[x][y] = 1;
for (int i = 0; i < 8; ++i) {
int nx = x + dir[i][0], ny = y + dir[i][1];
if (check(nx, ny)) dfs(nx, ny);
}
}
double getdis() {
double ans = 0;
for (int i = 0; i + 1 < v.size(); ++i) {
for (int j = i + 1; j < v.size(); ++j) {
double dx = v[i].first - v[j].first, dy = v[i].second - v[j].second;
ans += sqrt(dx * dx + dy * dy);
}
}
return ans;
}
map<ll, char> mp;
char now = 'a';
void solve() {
double dis = getdis();
ll tmp = ll(dis * 1e6);
if (!mp[tmp]) mp[tmp] = now++;
for (auto it : v) s[it.first][it.second] = mp[tmp];
}
int main() {
scanf("%d%d", &m, &n);
rep(i, 1, n) scanf("%s", s[i] + 1);
rep(i, 1, n) rep(j, 1, m) {
if (s[i][j] == '1') {
v.clear();
dfs(i, j);
solve();
}
}
rep(i, 1, n) puts(s[i] + 1);
}