【搜索】B045_hc_不同類型的島嶼(dfs + Hash)

一、Problem

給你一張某一海域衛星照片,你需要統計:

  1. 照片中海島的數目
  2. 照片中面積不同的海島數目
  3. 照片中形狀不同的海盜數目

其中海域的照片如下,".“表示海洋,”#"表示陸地。在"上下左右"四個方向上連在一起的一片陸地組成一座島嶼。

.####..  
.....#.  
####.#.  
.....#.  
..##.#.  

上圖所示的照片中一共有4座島嶼;其中3座面積爲4,一座面積爲2,所以不同面積的島嶼數目是2;有兩座形狀都是"####",所以形狀不同的島嶼數目爲3。

輸入

第一行包含兩個人整數:N 和 M,(1 ≤ N, M ≤ 50),表示照片的行數和列數。

以下一個 N * M 的矩陣,表示表示海域的照片。

輸出

輸出3個整數,依次是照片中海島的數目、面積不同的海島數目和形狀不同的海島數目。

樣例輸入
5 7
.####..  
.....#.  
####.#.  
.....#.  
..##.#. 

樣例輸出
4 2 3 

二、Solution

方法一:dfs

  • 求島嶼數量 num 是簡單的…
  • 求島嶼面積的個數也不難,在搜索的時候保存陸地的 # 個數即可…
  • 比較麻煩的是求島嶼的形狀,這裏有一種比較簡單的思路:
    • 以第一行中 .#### 爲例,各個島嶼的座標分別爲 (0, 1)(0, 2)(0, 3)(0, 4),而相對於 (0, 1) 的相對座標爲 (0, 0)(0, 1)(0, 2)(0, 3)
    • 第三行的 "####" 的座標分別爲 (2, 0)(2, 1)(2, 2)(2, 3),它們相對 (2, 0) 的位置座標也是 (0, 0)(0, 1)(0, 2)(0, 3)
    • 結論:兩個島嶼的形狀相同當且僅當它們的相對位置序列完全相同。
  • 可行的做法:
    • 用二叉搜索樹保存每個座標的 hash 值。
import java.util.*;
import java.math.*;
import java.io.*;
public class Main{
	 static class Solution {
		int R, C;
		char[][] grid;
		final int[][] dir = { {1,0},{0,-1},{0,1},{-1,0} };
		
		int hash(Pos t) {
			return t.x*R+t.y;
		}
		void dfs(Pos c, Pos p, Set<Integer> set) {
			set.add(hash(c) - hash(p));
			for (int k = 0; k < 4; k++) {
				int tx = c.x + dir[k][0];
				int ty = c.y + dir[k][1];
				if (!inArea(tx, ty) || grid[tx][ty] == '.')
					continue;
				grid[tx][ty] = '.';
				dfs(new Pos(tx,ty), p, set);
			}
		}
		
		void init() {
			Scanner sc = new Scanner(new BufferedInputStream(System.in));
			R = sc.nextInt();
			C = sc.nextInt();
			grid = new char[R][C];
			
			for (int i = 0; i < R; i++) {
				String s = sc.next();
				for (int j = 0; j < C; j++)
					grid[i][j] = s.charAt(j);
			}
			int num = 0;
			Set<Integer> area = new HashSet<>();
			Set<Set<Integer>> shape = new HashSet<>();
			
			for (int i = 0; i < R; i++)
			for (int j = 0; j < C; j++) {
				if (grid[i][j] == '#') {
					Set<Integer> set = new HashSet<>();	//保存相對座標的數量
					Pos t = new Pos(i, j);
					dfs(t, t, set);
					num++;
					area.add(set.size());
					shape.add(set);
				}
			}
			System.out.printf("%d %d %d", num, area.size(), shape.size());
		}
		boolean inArea(int x, int y) {
			return x >= 0 && x < R && y >= 0 && y < C;
		}
		class Pos {
			int x, y;
			Pos(int _x, int _y) {x = _x;y = _y;}
		}
	}
	public static  void main(String[] args) throws IOException {  
		Solution s = new Solution();
		s.init();
	}
}

複雜度分析

  • 時間複雜度:O()O()
  • 空間複雜度:O()O()

方法二:


複雜度分析

  • 時間複雜度:O()O()
  • 空間複雜度:O()O()
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章