http://tioj.ck.tp.edu.tw/problems/1684
有趣的圖論題,感覺很複雜,結果難得傳一次就AC~~。
跟點雙連通有關。
題目是有一堆圓桌武士,它們之間可能會互相仇恨。
每次聚會時必須符合 1. 人數是奇數 2.互相仇恨的人不能做在相鄰的位置。
如果依照此規則,有些人沒辦法參加任何聚會,輸出不能參加任何聚會的人數。
我們先把題目給的仇恨關係建成反圖,也就是互相不仇恨關係,所以 A 跟 B 有邊若且為若 A 跟 B 可以坐一起。
然後我們發現只要一個點屬於一個奇環(有奇數個點的環),那他一定有辦法參加聚會(那個奇環剛好可以湊一桌,滿足奇數個人、每個相鄰的都不討厭對方)。
所以題目變成有幾個點不屬於任何奇環。
這題要用到一個很神奇的性值:一個點雙連通分量中存在奇環,若且為若這個分量中所有點都在奇環的附蓋下。
這個性質感覺不太難證,因為點雙連通分量中任意兩個點間都有至少兩條路徑,如果有一個奇環,不在奇環上的某個點 A,一定會連到奇環上的至少兩個相異點(連到同一個點的話那個點就是割點,點雙連通中不存在割點),於是那兩個點把奇環切成奇數長路徑跟偶數長路徑,這樣一定可以用這兩條路徑跟A到奇環的兩條路徑湊出一個包含A的奇環。
所以只要一個點雙連通裡有奇環就標記掉所有在雙連通裡的點,沒被標到的點的數量就是答案。
至於怎麼找雙連通,運用 Tarjan’s Alogrithm找割點的概念,並且在每次進去DFS的時候把點加入Stack裡,如果一個子節點的 low 值大於等於自己的 dfs值,就代表自己是割點,也代表剛剛進去DFS那一群點是一個雙連通分量(屬於其他雙連通分量的點都在遞迴時被拔掉了),那就把Stack裡的點POP出來(POP到剛剛的子節點),同時在DFS的時候進行著色,如果戳到一個走過的點就跟她進行比較,如果顏色一樣代表有奇環,return 時 回傳 true,在POP點時如果剛剛DFS時是true代表此雙連通有奇環,全部標記掉(記得標記現在的點)。
然後root記得也要判,其實也就是root有第二個子節點以後的子節點全都是獨立的雙連通分量。
最後DFS完剩下的一群點(還在Stack裡的)也是一個雙連通,不要忘記標記了。
好像有點複雜,其實就是DFS時維持這個DFS Tree沒有割點,有就把會被割掉的部分拔掉,這樣就沒有割點了。
有沒有奇環的變數,如果這個點是割點就做上面做的事,不是割點了話要記錄起來,最後return回去。
PS.其實可以找出雙連通後再DFS一次著色,但是我喜歡壓成一個DFS。
1 |
|