APCS 病毒演化 (zerojudge f582)
科學家發現了 \(n\) 種病毒,編號分別是 \(1\) 到 \(n\),已知每一種病毒可以用一個 RNA 序列來表達,RNA 序列是一個長度為 \(m\) 的字串,其中包含 A、U、C、G、@等字元,其中 @ 為科學家沒觀察清楚的位置,可能為 A、U、C、G 其中任何一種。 科學家也研究出了這些病毒的演化關係,除了一個最原始的病毒以外,每一種病毒都是從另一個病毒演化而來的,這些病毒會構成一個樹狀結構的病毒族譜 (如圖)。
兩個 RNA 序列的的距離定義為它們的漢明距離,也就是相異的位數個數。更具體的說,對於兩個長度都是 \(m\) 的 RNA 序列 \(a, b\),它們的漢明距離就是有幾個位置 \(i\) 滿足 \(a_i\neq b_i\) 。
你想知道目前的病毒族譜的每一個 RNA 序列中的 @ 字元的填入 A、U、C、G 中的其中一個字元後,每一個病毒與它演化來源的病毒的距離總合最小值是多少? (後面就簡稱最小演化距離)
解題思路:
這題我是用 DP 寫,並使用 DFS 從根遍歷整棵樹,在過程完成狀態轉移。
在寫這題的時候,最困難的應該就是要想怎麼定義狀態還有狀態轉移如何在 \(O(1)\) 內做出來。
把這題看作是求 \(m\) 次 RNA 長度為 \(1\) 時的最小演化距離(把一串 RNA 拆成 \(m\) 個字元分開處理) ,最後再把這 \(m\) 個最小演化距離相加即可。
不妨定義 \(dp[i][j][k]\) 代表目前單獨處理第 \(j\) 個字元,點 \(i\) 病毒 RNA 序列的第 \(j\) 個字元為 \(k\) 時,求該點為根節點時的最小演化距離 (A, U, C, G 分別對應到 \(k = 1, 2, 3, 4\) ) ,而當點 \(i\) 病毒序列中的第 \(j\) 個字元已經被定義時 (也就是不為 @ 時) ,就將 \(k\) 為其餘狀態的最小演化距離設為極大值。
在狀態轉移時,就會是所有子樹的子節點在四種狀態的最小演化距離,加上與當前結點的距離 (就是看子節點當前狀態是否跟父節點一樣,一樣距離就是 0 不一樣就是 1) 的最小值,以數學式表達如下 (其中 \(child\) 代表第 \(i\) 個陣列的子節點個數, \(child_p\) 代表點 \(i\) 第 \(p\) 個子節點) :
\[dp[i][j][k] = \sum_{p=1}^{child} min(dp[child_p][j][1] + (k != 1), dp[child_p][j][2] + (k != 2), dp[child_p][j][3] + (k != 3), dp[child_p][j][4] + (k != 4))\]
而最後答案就是:
\[\sum_{j=0}^{m-1} min(dp[root][j][1], dp[root][j][2], dp[root][j][3], dp[root][j][4])\]
總複雜度為 \(O(nm)\)
🌟 在當沒有小孩時 (葉節點) ,以其做為根的最小演化距離 (dp 值) 除了被設為極大值的狀態外,均為 0。
1 |
|