2.10 模擬賽總結
2.10 模擬賽總結
A. 希望
題意:
給一張 \(N\times M\) 的網格圖,圖中存在若干關鍵點,其中關鍵點一定不在圖的最左或最右兩列。
你需要走一條包含點 \((1,1)\) 的歐拉回路,滿足:
- 該回路經過所有關鍵點;
- 只有在圖的最左邊或最右邊兩列時可以沿縱向走,在任意時刻都可以沿橫向走。
求路徑的最小長度。
\(N\le10,M\le50\)。
做法:
我們記圖中第一列和最後一列的所有點叫邊緣點。
注意到若某個關鍵點被經過了,則其所在的那行裡,一定存在一個邊緣點被經過了一次,
因為對於這一行內的一個關鍵點,只有到達了這一行的邊緣點後,才可能沿橫向走到該關鍵點。
同時,當每個邊緣點是否被經過的狀態確定後,不同行內部如何抉擇是互不影響的,
那我們現在來討論一下,對於具體的一行裡兩個邊緣點狀態的所有可能,分別該如何決策。
顯然,一行內的一個關鍵點不會被經過多次,否則我們一定可以將方案調整成只經過一次且會更優,
而我們進入行的途徑只有邊緣點,故我們必然分別從兩邊緣點往行內走 \(x\in[0,m]\) 步,
再返回當前邊緣點或者到達另一端的邊緣點後繼續沿縱向行走。
而當邊緣點未經過過時需滿足步數 \(x=0\),且兩邊走的步數之和小於 \(m\)。
形式上的,我們記該行左右兩個邊緣點分別是 \(u\) 和 \(v\),如果一個點 \(p\) 曾被經過,則其狀態 \(s(p)=1\)。
首先,如果 \(s(u)=1\),則我們可以選擇從 \(u\)
其次,如果 \(s(v)=1\),則我們可以選擇從 \(v\) 出發到該行最左端的關鍵點再回到 \(v\) 點或繼續走到底;
最後,如果 \(s(u)=s(v)=1\),則我們可以選擇分別從 \(u,v\) 出發,分別到達一對相鄰關鍵點再返回。
當然,如果該行內沒有關鍵點,我們也可以選擇不管這一行。
又因為不同行內部如何抉擇是互不影響的,
所以容易想到的是利用 狀壓DP
的思想,即記錄當前座標以及當前每一行的行走情況來求解。
具體來說,我們設計一個含有 \(O(N5^N)\) 個狀態的 狀壓DP
,即:
記 \(f(i,j,S)\)
該位的五種不同的值,分別代表了該行:
從未走過,被橫穿了一次,左邊緣點曾被經過,右邊緣點曾被經過,兩邊緣點都曾被經過。
這樣的話,我們只需要處理每種狀態是否可能出現以及出現這種狀態的花費,
最後在額外計算每行沒有處理過的花費即可。
但上述方法並不能通過,而實際上這個做法還有優化空間。
但是我們發現,在轉移時,下列三種選擇對原狀態造成的影響是類似的:
橫穿一行,只從左邊緣點進入並返回,以及只從右邊緣點進入並返回。
我們發現,這三種選擇都讓當前一整行不再需要考慮,而唯一的區別是最後新到達的邊緣點位置,
故我們可以考慮不單獨記錄被橫穿,而是記錄一個數量為 \(4^N\) 的狀態,其中第 \(t\) 行對應的狀態有:
從未走過,左邊 / 右邊走了一部分但沒有走完整行,整行的關鍵點全走了一次。
這樣的狀態就顯然是是完備且可以轉移的了,
時間複雜度為 \(O(N^24^N)\),空間複雜度為 \(O(N4^N)\)。
C. 命運
題意:
給一張 \(N\) 個點 \(M\) 條邊的無向圖,請求出圖的所有滿足不存在三元環的點匯出子圖個數。
\(N,M\le60\)。
做法:
首先,暴力的做法是列舉原圖中每個點的狀態,即該點是否出現在匯出子圖中,
再對每個匯出子圖暴力的統計其是否包含三元環,這樣的複雜度是 \(O(2^NN^3)\) 的。
我們考慮優化這個暴力,一個很靈巧的想法是考慮能否只列舉一部分點而達到同樣的效果。
那假設我們只枚舉了點集 \(S\) 中的點,記不在 \(S\) 中的點集為 \(T\),我們考慮 \(T\) 滿足什麼性質時能正確計數。
我們發現,如果 \(T\) 是若干個樹,環,或鏈這樣的一些特殊結構時,我們就可以採用 DP
來計數,
那也就是說,我們只要能恰當的去選這個 \(S\) 集合,
使得 \(S\) 的大小足夠小,且 \(T\) 中只有我們希望出現的結構,那麼這個問題就解決了。
那最終的問題就是如何選 \(S\) 集合,我們只需要採用如下的方法即可:
我們建一張新圖 \(G\),初始為原圖,我們一次次從將 \(G\) 中所有度數大於 \(2\) 的點和與其相連的邊刪除,
最後無法從 \(G\) 中刪點時,所有我們刪去的點集就是我們需要的 \(S\) 的一個足夠優的解。
為什麼?首先,這樣得到的 \(S\) 對應的 \(T\) 一定只存在若干個鏈和環,原因是所有點的度數都小於 \(3\),
而只有鏈和環能滿足這個度數的要求,而因為一次刪點的同時會伴隨著刪至少 \(3\) 條邊,
故總刪邊次數不超過 \(\frac{M}{3}\) 次,故 \(S\) 的大小最大也就是 \(\frac{M}{3}\)。
那麼,我們的時間複雜度就是 \(O(2^{\frac{M}{3}}N)\) 的,已經足以通過本題。
最後,我們討論怎麼使用 DP
來對 \(T\) 計數,這個是好做的,具體來說:
首先,每個 \(T\) 中的連通塊是獨立的,我們可以分開計數,最後再把方案數乘在一起;
而對於一個連通塊,其只能是一條鏈或環,我們考慮對 \(T\) 方案的限制只有如下兩種:
其一是,一個 \(S\) 中出現在匯出子圖中的點與 \(T\) 中的一對相鄰點分別有邊,
則這對點不能同時出現在匯出子圖中,
其二是,一對 \(S\) 中出現在匯出子圖中的相鄰點與 \(T\) 中的一個點分別有邊,
則這個 \(T\) 中的點不能出現在匯出子圖中。
也就是說,在列舉 \(S\) 中點的狀態後,我們對 \(T\) 的限制只有一個點不能選,或一對相鄰點不能同時選。
而這些限制在鏈或環上都是好處理的,我們直接 DP
計數即可。