1. 程式人生 > 其它 >AcWing1402. 星空之夜

AcWing1402. 星空之夜

技術標籤:AcWing演算法AcWing

  1. 題目

    夜空深處,閃亮的星星以星群的形式出現在人們眼中,形態萬千。

    一個星群是指一組非空的在水平,垂直或對角線方向相鄰的星星的集合。

    一個星群不能是一個更大星群的一部分。

    星群可能是相似的。

    如果兩個星群的形狀、包含星星的數目相同,那麼無論它們的朝向如何,都認為它們是相似的。

    通常星群可能有 8 種朝向,如下圖所示:

    在這裡插入圖片描述

    現在,我們用一個二維 01 矩陣來表示夜空,如果一個位置上的數字是 1,那麼說明這個位置上有一個星星,否則這個位置上的數字應該是 0。

    給定一個夜空二維矩陣,請你將其中的所有星群用小寫字母進行標記,標記時相似星群用同一字母,不相似星群用不同字母。

    標註星群就是指將星群中所有的 11 替換為小寫字母。

  2. 輸入格式

    第一行包含一個整數 W,表示矩陣寬度。

    第二行包含一個整數 H,表示矩陣高度。

    接下來 H 行,每行包含一個長度為 W 的 01 序列,用來描述整個夜空矩陣。

  3. 輸出格式

    輸出標記完所有星群后的二維矩陣。

    用小寫字母標記星群的方法很多,我們將整個輸出讀取為一個字串,能夠使得這個字串字典序最小的標記方式,就是我們想要的標記方式。

    輸出這個標記方式標出的最終二維矩陣。

  4. 資料範圍

    0≤W,H≤100
    0≤ 星群數量 ≤500,
    0≤ 不相似星群數量 ≤26,
    1≤ 星群中星星的數量 ≤160

  5. 輸入樣例

    23
    15
    10001000000000010000000
    01111100011111000101101
    01000000010001000111111
    00000000010101000101111
    00000111010001000000000
    00001001011111000000000
    10000001000000000000000
    00101000000111110010000
    00001000000100010011111
    00000001110101010100010
    00000100110100010000000
    00010001110111110000000
    00100001110000000100000
    00001000100001000100101
    00000001110001000111000
    
  6. 輸出樣例

    a000a0000000000b0000000
    0aaaaa000ccccc000d0dd0d
    0a0000000c000c000dddddd
    000000000c0b0c000d0dddd
    00000eee0c000c000000000
    0000e00e0ccccc000000000
    b000000e000000000000000
    00b0f000000ccccc00a0000
    0000f000000c000c00aaaaa
    0000000ddd0c0b0c0a000a0
    00000b00dd0c000c0000000
    000g000ddd0ccccc0000000
    00g0000ddd0000000e00000
    0000b000d0000f000e00e0b
    0000000ddd000f000eee000
    
  7. 樣例解釋
    樣例對應的星空圖如下:
    在這裡插入圖片描述
    答案對應的標記後星空圖如下:
    在這裡插入圖片描述

  8. 程式碼1

    import java.util.*;
    import java.io.*;
    
    public class Main {
        static List<Double> hash = new ArrayList<>();
        static List<
    int[]> q = new ArrayList<>(); static int col; static int row; static char[][] g; public static void main(String[] args) { Scanner sc = new Scanner(System.in); // 指定星圖的行和列 col = sc.nextInt(); row = sc.nextInt(); // 用g儲存整個星圖 g = new char[row][col]; for(int i = 0; i < row; i++) { String str = sc.next(); g[i] = str.toCharArray(); } for(int i = 0; i < row; i++) { for(int j = 0; j < col; j++) { // 如果當前座標是星星 if(g[i][j] == '1') { q.clear(); dfs(i, j); // 獲取星圖的hash值 double val = get_hash(); // 不同hash值對映為字元 char c = get_char(val); for(int[] k: q) { int a = k[0]; int b = k[1]; g[a][b] = c; } } } } for(int i = 0; i < row; i++) { System.out.println(g[i]); } } // 遍歷座標[x, y], 將其相接觸(8個方向)的星雲儲存在同一個列表中 public static void dfs(int x, int y) { q.add(new int[]{x, y}); g[x][y] = '0'; // 這裡就是相鄰的8個表格 for(int i = x - 1; i <= x + 1; i++) { for(int j = y - 1; j <= y + 1; j++) { if(i >= 0 && i < row && j >= 0 && j <col &&g[i][j] == '1') { dfs(i, j); } } } } // 計算星圖的hash值 // 用星圖中任意兩個座標之間的距離之和來表示該星圖的hash值 // 雖然也存在不同圖形有相同hash值的情況, 但是概率很低很低, 可以忽略 public static double get_hash() { double res = 0; for(int i = 0; i < q.size(); i++) { for(int j = 0; j < q.size(); j++) { res += get_dist(q.get(i), q.get(j)); } } return res; } // 不同hash值對映為字元 public static char get_char(double val) { for(int i = 0; i < hash.size(); i++) { // 如果當前hash值和列表中的元素值相差很小(1e-6) // 則直接返回該元素對應的字元 if(Math.abs(val - hash.get(i)) < 1e-6) { return (char)((i) + 'a'); } } // 如果沒有, 則新增到列表中, 並返回對應的字元 hash.add(val); return (char)((hash.size() - 1) + 'a'); } // 計算兩點間的距離 public static double get_dist(int[] a, int[] b) { return Math.sqrt((a[0] -b[0]) * (a[0] - b[0]) + (a[1] - b[1]) * (a[1] - b[1])); } }