AcWing 1402. 星空之夜 (FloodFill 哈希 搜索)

題目描述

原題連接html

分析

一個星羣就對應一個連通塊, 題目所求即將二維矩陣中類似的連通塊用同一符號標記出來.
首先要找出矩陣中全部的連通塊, 能夠藉助FloodFill算法搜索出全部的連通塊
接下來如何找到類似的連通塊呢? 咱們採用哈希的方式

咱們發現上圖類似星羣兩點間的歐幾里得距離 ( ( x 1 − x 2 ) 2 + ( y 1 − y 2 ) 2 ) (\sqrt{(x_1 - x_2)^2 + (y_1 - y_2)^2}) ((x1x2)2+(y1y2)2 )之和是相同的
咱們即可以該距離之和做爲哈希表的 k e y key key, 符號表示做爲哈希表的 v a l u e value value
這樣類似的星羣就會被映射成同一個符號表示
從而獲得答案ios

看不懂就參考Y總視頻講解web

實現

#include <cstdio>
#include <iostream>
#include <map>
#include <cmath>
using namespace std;
const int N = 109;
const double eps = 1e-6;
int m, n;
int cnt; // 記錄當前連通塊中方格數量
int dx[] = {0,1,1,1,0,-1,-1,-1}, dy[] = {1,1,0,-1,-1,-1,0,1}; // 八方向連通,不是四方向
char w[N][N]; // 儲存二維01矩陣
char ans[N][N]; // 輸出最終的結果矩陣
pair<int, int> pos[N*N]; // 記錄當前連通塊各方格的座標
double hashTable[30]; // 最多有26種星雲
int index; // 記錄當前已經出現過的字符種類的數量
bool check(int x, int y) // 判斷當前位置是否合法
{
    if(x < 0 || y < 0 || x >= n || y >= m) return false;
    if(w[x][y] == '0') return false;
    return true;
}
void dfs(int x, int y) // 搜索連通塊
{
    pos[cnt].first = x, pos[cnt].second = y, cnt++;
    w[x][y] = '0'; // 標記一下表明已經搜過
    for(int i = 0; i < 8; i++)
    {
        int nx = x + dx[i], ny = y + dy[i];
        if(check(nx, ny)) dfs(nx, ny);
    }
    return;
}
double get_hash() // 計算當前連通塊的哈希值, 即兩點間的歐幾里得距離之和
{
    double sum = 0;
    for(int i=0; i<cnt-1; i++)
    {
        for(int j=i+1; j<cnt; j++)
        {
            int x1 = pos[i].first, x2 = pos[j].first, y1 = pos[i].second, y2 = pos[j].second;
            sum += sqrt((x1-x2)*(x1-x2) + (y1-y2)*(y1-y2));
        }
    }
    return sum;
}
char get_ch(double key) // 根據哈希函數的key找到對應的字符value
{
    for(int i=0; i<index; i++)
    {
        if(fabs(key - hashTable[i]) <= eps) // 可能有偏差
            return 'a' + i;
    }
    hashTable[index++] = key;
    return 'a' + index - 1;
}
int main()
{
    cin >> m >> n;
    for(int i=0; i<n; i++)
    {
        for(int j=0; j<m; j++)
        {
            cin >> w[i][j]; // debug: 題目輸入是字符串
            ans[i][j] =  w[i][j];
        }
    }
    for(int i=0; i<n; i++)
    {
        for(int j=0; j<m; j++)
        {
            if(w[i][j] == '0') continue;
            cnt = 0; // 從新計數
            dfs(i, j);
            char c = get_ch(get_hash());
            for(int i=0; i< cnt; i++)
            {
                int x = pos[i].first, y = pos[i].second;
                ans[x][y] = c;
            }
        }
    }
    for(int i=0; i<n; i++)
    {
        for(int j=0; j<m; j++)
        {
            cout << ans[i][j];
        }
        cout << endl;
    }
    return 0;
}
相關文章
相關標籤/搜索