APCS 血緣關係 (zerojudge b967)
下圖為家族的關係圖:0 是 7 的孩子, 1、2 和 3 是 0 的孩子, 4 和 5 是 1 的孩子, 6 是 3 的孩子。 可以發現最遠的親戚關係為 4 (或 5) 和 6,他們的” 血緣距離” 是 4 (4→1→0→3→6)。 給予任一家族的關係圖,請找出最遠的” 血緣距離”。
解題思路:
這題是要求所謂的 樹直徑(整個祖譜就可以看成是一顆樹,要求相距最遠就是樹直徑了) 我做這題的方法是在 dfs 遍歷整棵樹的同時,紀錄從葉子到各子樹的最大節點數(也就是那個節點到子葉的層數,後面稱為 rank)以及各子樹的中最大直徑,同時取出各子樹中第一深跟第二深的為 max_rank、second_rank,如此目前節點的直徑就會是:
\[max(children\_max\_distance, max\_rank+second\_rank+1)\]
(直觀想的話會以為該節點為根節點的樹直徑是第一深 + 第二深的層數 + 自己這個節點,但還要考慮到可能子樹中已經有更大直徑的狀況,還有只有一個節點、或本身就是葉子的狀況,但因為此時的 second_rank 或是 max_rank、second_rank 會是 0,因此同樣會是 max_rank+second_rank+1)
該節點的最大層數就會是子樹的最大層數 + 1 (而當本身是葉子時就是 1,但因為此時 max_rank 是 0,因此這個 special case 寫的時候不用也不用特別限制)
另外我為了實作方便,我把 max_distance 獨立成一個變數,不跟 dfs 的遞迴寫在一起,這樣寫起來也比較簡單 其他更詳細的實作細節可以看底下程式碼的註解
🌟 如果確定時間複雜度是 \(O(n)\) 但還是 TLE 的話,有可能是你沒加上輸入輸出優化 ios::sync_with_stdio(0);cin.tie(0); cout.tie(0);
,但這題好像有點刁鑽,所以可能還需要再快一些才會過,像是我後來就發現不能夠 memset,因為不用每次都把整個陣列初始化,有要用到的再設回 0 就好了,另外也有人講到可以把 cin/cout 全部改成 printf/scanf 會更快,不過我是把 memset 改掉之後就成功 AC 了,或者你可以試試看多丟幾次,我丟上去 AC 的程式執行時間有差到快一秒的,可以多試幾次。
1 |
|