Divide and Conquer

28  Download (0)

Full text

(1)

Divide and Conquer

課堂補充 by TreapKing

(2)

Q&A Q&A

• 影片都看過了嗎?

• 對於影片的內容有沒有什麼問題?

• 雖然每次這樣問都沒人理我……

(3)

平面最近點對

Closest Pair (?

(4)

題目題目

• 在平面上給你 N 個點,要你找出歐式距離最短的兩個點。

• N <= 100,000

(5)

naïve 作法 naïve 作法

• 開心 CN 取 2 = O(N2)

• 顯然會壞掉 QQ

• 如果在平面上想要做 divide and conquer ,該怎麼分割問題?

(6)

平面 D&C 平面 D&C

• 我們可以先把所有輸入的點照 x 座標排序後,在中間畫一條分 隔線。

• 這樣可能的答案就分成 ( 兩個點都在左邊 ) 、 ( 兩個點都在右 邊 ) 、 ( 橫跨分隔線 ) 三種情況

• 一些平面上的 D&C 題都會做類似的事。

• 顯然只有點對橫跨分隔線的情況需要討論,如果這個情況可以解 決的話,其他兩個情況只要遞迴下去解就好了。

(7)

思考一下思考一下

• 如果只是要算分隔線兩邊的最近點對,有什麼好方法嗎?

• 因為 x 座標的大小關係已經確立了,所以可以把兩邊直接照 y 座標排序

• 然後就發現還是好困難喔 .___.

(8)

剪枝!?剪枝!?

• 定神一想,會發現如果遞迴下去後找到的最近點對的距離是 d

,那麼我們根本就不需要考慮那些距離超過 d 的點對

• 所以離分隔線超過 d 的點都不需要去考慮。

• 對於每個點,也只有 y 座標差距不超過 d 的點可能可以讓你 找到更近的點對

• 聽起來只是個壓常數的剪枝,但在什麼情況下,這個做法一樣會 退化成 N2 呢?

• 因為已經知道各自的最近點對的距離是 d ,所以每個點附近的 點不會太多 !

• 附近的點只會有常數個,所以直接跑下去複雜度就是好的!

(9)

多項式乘法

Polynomial Multiplication

(10)

多項式乘法 多項式乘法

• 給你兩個 n 次多項式,請你印出兩個多項式的乘積。

• Ex:

(11)

不就只是乘法 不就只是乘法

• Naïve 作法

• 用個雙重迴圈跑一跑乘一乘加一加

• 時間複雜度是 O(n2)

• 據說在古早的時代,從來沒有人質疑過乘法可以做得更快

• 可能會有人想到 FFT ,但我現在沒有要講這個 XD

(12)

一些小觀察 一些小觀察

• 把多項式表達為

• 同理:

• 順便不失一般性的假設 n+1 是 2 的次方 ( 如果不是的話,就加入 一些係數為 0 的高次項 )

(13)

一些小觀察 一些小觀察

• 既然是要教分而治之 (fun and j_zz)法,那就先把多項式切兩半看看

• 令

• 同理

• 所以

(14)

一些小觀察 一些小觀察

• A, B, C, D 都是 (n/2) 次的多項式

• 所以只要做四次比較小的乘法就可以解決原問題了!

• 成功切成子問題 => Divide & Conquer!

• 可是,這樣真的有比較快嗎?

• 用個很不嚴謹的感覺會發現,我們好像沒有真的減少了什麼運算

• 事實上這樣做的複雜度還是 O(n2) 的

(15)

更多觀察更多觀察

• 我們想要算的東西是

• 如果我們計算

• 就可以把原本的式子化為

• 因為加 / 減法只需要花 O(n) ,這樣子我們只用了 3 個乘法

(16)

D&C on 多項式乘法 D&C on 多項式乘法

• 看起來我們得到了一個比較快的做法

• 那麼,這樣的時間複雜度是多少呢?

• 設這個做法解 n 次多項式花的時間是 T(n) ,那麼我們會得到這 個遞迴式:

• 如果你已經猜到某個複雜度的話,可以用歸納法去證明它

• 這裡介紹一個更強的工具

(17)

主定理 (Master Theorem) 主定理 (Master Theorem)

reference: 隨機客的演算法投影片

(18)

帶個數字帶個數字

• 對於

• 可以發現顯然是對應到主定理的 Case 1

• 因此我們可以得知這個做法的複雜度為

(19)

樹分治

Divide and Conquer on Tree

(20)

樹分治樹分治

• 顧名思義是在樹上做分治

• 一如往常先給一個例題再說

(21)

例題例題

• 給你一顆 N 個點的樹,每條邊的邊權都是 1 ,問你這棵樹上 有幾條路的路徑不大於 k

• N, k <= 100,000

(22)

來點 naïve 作法 來點 naïve 作法

• 面對這題可以怎麼做呢?

• 枚舉 N2 種路徑, O(N) 算一下他們的長度,總複雜度 O(N3)

• 枚舉起點, DFS or BFS 遍歷整棵樹數有幾條路徑長 <=k , O(N2)

• 不過我們顯然要找到一個不用枚舉路徑的方法

• 這週的主題是分治,所以一定是要找一個分治的解法!

(23)

試著亂分治一通 試著亂分治一通

• 如果把原本的樹分成兩棵樹看看。

• 假設原本的樹被一條 a-b 邊切開,那麼答案就等於 (a 那邊的路徑數 )+(b 那邊 的路徑數 )+( 經過 a-b 邊的路徑數 )

• 前兩項可以分治下去,第三項可以怎麼算呢?

• 花 O( 子樹大小 ) 可以找到所有以 a 或 b 為起點的所有路徑

• 設 da[k] 為以 a 為起點,長度為 k 的路徑的數量, db 同理

• 跨 a-b 邊且長度不大於 k 的路徑數 = da[0]*db[0:k-2] + da[1]*db[0:k-3]

+ ……

• 所有操作都是 O( 子樹大小 )

• 如果每次都可以找到好的 a-b 邊把整顆樹切一半的話,複雜度就會是 O(NlgN)

(24)

所以要怎麼砍樹?

所以要怎麼砍樹?

• 要怎麼找 a-b 邊讓每次的樹都盡量變兩半呢?

• 定神想一分鐘,就會發現星狀圖直接沒救

• 如果不是找一條邊,而是找出一個點呢?

• 以防又白想了一陣,先確保我們可以找到「好點」

• 所以一定存在一個好點,拔掉這個點後,剩下的子樹都不大於原 本的樹的大小的一半

• 總之好點就是存在啦,如果你是沒來上課事後才載投影片下來看 的話,那就請你自己想辦法證一證

(25)

step by step step by step

• 套回分治的框架

• 1. 找到一個好點 g

• 2. Divide ,把這個點的所有兒子子樹們遞迴下去求解

• 3. Merge ,計算所有通過 g 且長度不大於 k 的路徑數

• 真正的問題在 1. & 3.

(26)

good point good point

• 用一個 dfs 找出對於每個點 u ,以 u 為根的子樹的大小,設為 sz [u]

• 對於每個點 v ,設 v 的兒子們為 t1, t2, …

• 拔掉 v 後,剩下的子樹 size 為 N-sz[v], sz[t1], sz[t2], …

• 先前證明過一定有個點可以讓剩下的子樹大小都不超過原本的一 半

(27)

merge merge

• 剛剛我們已經介紹過兩個子樹要怎麼合併,那 t 個子樹呢?

• 直接 Ct 取 2 的話複雜度會慘掉

• 先做 1 - 2 ,再做 1&2 – 3 ,再做 1&2&3 – 4……

• 這樣複雜度就會是好的!

(28)

實作上的細節 實作上的細節

• 算子樹的時候,可以把拔掉的點設成不能走,各種 dfs 的時候不 要走到被拔掉的點上面

• 注意一下遞迴的時候做事情的順序,有些全域陣列可能遞迴下去 之後會被改掉。

Figure

Updating...

References

Related subjects :