• 沒有找到結果。

Flood Fill Algorithm

N/A
N/A
Protected

Academic year: 2022

Share "Flood Fill Algorithm"

Copied!
18
0
0

加載中.... (立即查看全文)

全文

(1)

Flood Fill Algorithm

by Chin Huang Lin

(2)

關於淹水……

關於淹水……

• 想像你往一個空的冰塊盒裡面倒水……

• 溢出來的水,會以什麼樣的方式填滿整個格子呢?

• 也許有些格子還有完整的冰塊,作為障礙物

(3)

如何實作?

如何實作?

• Naïve idea: 每次都檢查所有格子,並且讓它們「淹」到鄰居格

• 假設冰塊盒大小是 ,那每次都要 檢查

• 總共最多需要 回合 ( 想想看,為什麼? )

• 複雜度

• 問題:花太多時間找出每回合要「溢出去」的格子了!

•  

(4)

仔細思考一下……

仔細思考一下……

• 其實每次都只有「最外圍」的格子需要往外淹

• 每個格子都只有一次當「最外圍」的機會!

• 長江後浪推前浪:每回合一定都是先把一些老的最外圍處理掉,然後產生 新的最外圍

• 乾脆用成一個 queue 就好啦!

(5)

Demo Demo

(6)

如何實作?

如何實作?

• 怎麼把一個「格子」放進 queue 裡?

1. 把格子的 座標包成一個 struct/class 2. 對 分別開一個 queue

• 有障礙物怎麼辦?

• 沒怎麼辦,就當作該格早就滿了即可

• 同時往多個格子裡加水怎麼辦?

• 一開始把所有加水格都丟到 queue 裡

• 邊界好麻煩怎麼辦?

• 假想一圈外圍 ( 例如 的冰塊盒就調整成 ) ,並且把外圍都標記成障礙物

• 模擬「淹水」的過程很麻煩,幾個方向就要寫幾個很大串的 if ,怎麼辦?

• 先自己想想看囉,我們上課時會討論這個問題 :D

• 提示:有沒有發現所有的 if 其實都長得很像?

•  

(7)

嶄新的複雜度 嶄新的複雜度

• 執行的回合數跟 queue 內元素個數有關,但每回合只拓展一格

• 所有會被淹到的格子都恰好會進入 queue 一次

• queue 內元素個數不超過格子個數,

• 對於每個元素,拓展都只需要 次操作

• 整體複雜度為

•  

(8)

看看練習題吧 ! 看看練習題吧 !

• Zerojudge d537 染色遊戲 ( 北縣 98 年學科能力競賽 )

http://zerojudge.tw/ShowProblem?problemid=d537

• 如果直接使用 Naïve 的方法實作:

• 其實當 時可以通過!甚至連 都行

• 如果使用剛剛的方式,擴散變成 了,可是要怎麼做到

1. 同時擴散 ( 剛剛是一格一格擴散 ) 2. 計算某顏色的數量呢?

•  

(9)

關於同時擴散……

關於同時擴散……

• 觀察一下我們的 queue ,不難發現在 queue 裡面「梯數」一定是非嚴格 遞增的

• ex. 起點為 (2,2), (4,5), (10,3)

• 為了方便起見,假設題目是四方位擴散

• queue 裡前幾個元素:

(2,2), (4,5), (10,3),

(2,3), (2,1), (1,2), (3,2), (4,6), (4,4), (3,5), (5,5), (10,4), (10,2), (9 ,3), (11,3),

(2,4), (1,3), (3,3), ……

• 紅色的是第一梯,藍色的是第二梯,綠色的是第三梯

• 也就是說,我們只需要多記錄每個格子的「梯數」,然後每回合都把 queu e 裡面最前面幾個同梯的都一口氣做完就可以了!

(10)

關於記錄顏色……

關於記錄顏色……

• 如果我們知道如何同時擴散,其實就知道怎麼維護每回合末的顏色個數了

• 一邊擴散,一邊記錄每種顏色的數量

• 每回合當梯的都擴散完以後直接查看我們的記錄即可

✶ 別忘了擴散時要注意到現在在擴散哪種顏色。理論上每個格子都會被擴散 三次!

(11)

有了剛剛的重大結論……

有了剛剛的重大結論……

• Zerojudge b224 喵喵抓老鼠 (2008 NPSC 國中組初賽 )

http://zerojudge.tw/ShowProblem?problemid=b224

• 這次要求的是最短路,跟淹水有什麼關係?

• 讓我們回到剛剛的結論……

• 觀察一下我們的 queue ,不難發現在 queue 裡面「梯數」一定是非嚴格遞增的

• 梯數代表什麼呢?不就是要走幾步才會到嗎?

• 又因為走每一步的成本都是 1 ,所以「梯數」恰好就是最短路!

• 想一想,為什麼?可以跟走每一步的成本不見得是 1 的情況比較,例如每個格子都有 一個高度值,從某格子走到鄰居格子需要的成本就是高度值的差

• 從起點開始「淹水」,淹到第一隻老鼠就可以停了

(12)

回顧一下……

回顧一下……

• 剛剛提到的淹水算法中,核心的資料結構是 queue

• 如果把 queue 換成 stack ,會發生什麼事情呢?

(13)

想像一下……

想像一下……

• 如果地圖很大,會看到水先往某個方向一直流,到盡頭才回來流其他方向

• 假如把方向看成學術領域的話:

• 用 queue 來做,就好像全部的領域都同時涉獵,並且一層一層學深入

• 用 stack 來做,就好像先一口氣專精某個領域,鑽研完了才鑽研其他領域

• 用 queue 來做,被稱為廣度優先搜索 (Breadth-first search, BFS)

• 用 stack 來做,被稱為深度優先搜索 (Depth-first search, DFS)

• 實際上, DFS 不會像剛剛提到的那樣實作

(14)

DFS 實作 DFS 實作

• 觀察一下剛剛的作法……

• 其實 2,3,4,5 沒有必要同時存在 stack 中!

• 推入一個,就直接做下去就好了

• 利用遞迴來實作!

(15)

Sample code Sample code

void dfs( int x, int y, int cur_dist ){

dist[x][y] = cur_dist;

if( map[x+1][y] != ‘#’ && dist[x+1][y] > cur_dist + 1 ) dfs( x+1, y, cur_dist + 1);

if( map[x][y+1] != ‘#’ ……

……

}

(x,y) = 當前所在的格子座標 cur_dist = 當前走的步數

dist[x][y] = 走到 (x,y) 的最短路長度

呼叫 (x0,y0,0) 即可求解所有格子的最短路,

其中 (x0,y0) 是貓貓所在

(16)

想一想 想一想

• 可不可以用 DFS 來做例題一?

• 可不可以用 DFS 來做例題二?

• 有沒有什麼壞處?

• 複雜度是多少呢?

• 如果題目是,每個格子都有一個高度值,高度值低於一定程度就會淹水,

請問到最後會有幾塊水窪,那麼用 BFS/DFS 都可以做嘛?

(17)

BFS vs DFS BFS vs DFS

• 資料結構

• queue vs stack

• 單位成本最短路中,最早找到的解就是解

• 可以 vs 不可以

• 空間消耗

• 最壞情況下一樣,但通常 DFS 比較省

• 有些情況下 DFS 使用的空間會少到有量級上的差異

• 好寫程度

• 需要維護 queue vs 利用遞迴維護 stack

• 例外情形

• DFS 若用遞迴實作須考慮 stack overflow

(18)

Is BFS better ? Is BFS better ?

• 乍看之下似乎 BFS 可以做到的事情比 DFS 還要多得多

• 事實上,在單純的 flood fill 中, DFS 並沒有特長之處;但在未來許多 的領域中, DFS 將有許多意想不到的表現

• 敬請期待 :p

參考文獻

相關文件

強制轉型:把 profit轉換成double的型態

最佳解裡面如果沒有greedy choice的話, 則想辦法 把最佳解裡面的一些東西和greedy choice互換. 結 果發現這個新解跟greedy choice一樣好

● size() 回傳 queue

Credit to Theory of Computer Games, 2018 Fall.. Normal BFS

Credit to Theory of Computer Games,

Credit to Theory of Computer Games, 2018 Fall.. Normal BFS

[r]

紅色 : 當今在的 Heap 被使用為合併後的 Heap...