Preface
說實話2-SAT的題目我都沒怎么做過,所以這里講的都是些超入門什么的
還有一些板子題,由於是暑假的時候學的所以有些我也記不清了
主要學習參考自:Manchery的課件&&dalao's blog&&Another dalao
What is 2_SAT?
SAT是適定性(Satisfiability)問題的簡稱 。一般形式為k-適定性問題,簡稱 k-SAT。
可以證明,當\(k>2\)時,k-SAT是NP完全的。因此一般討論的是\(k=2\)的情況,即2-SAT問題。
我們通俗的說,就是給你\(n\)個變量\(a_i\),每個變量能且只能取\(0/1\)的值。同時給出若干條件,形式諸如\((not)a_i\operatorname{opt}(not)\ a_j=0/1\),其中\(opt\)表示\(and,or,xor\)中的一種
而求解2-SAT的解就是求出滿足所有限制的一組\(a\)
Change 2-SAT into Graph Theory
首先我們考慮將2-SAT問題往圖論的方向靠,我們發現每個點要么取\(0\),要么取\(1\)。因此對於\(a_i\),我們建兩個點\(2i-1\)與\(2i\)分別表示\(a_i\)取\(0\)和\(1\)
然后我們考慮建邊來表示這些關系,我們令一條有向邊的意義:\(x\to y\)表示如果選擇了\(x\)就必須選\(y\)
那么我們可以舉一些簡單的例子來總結下連邊的規律(用\(i'\)表示\(i\)的反面):
- \(i,j\)不能同時選:選了\(i\)就要選\(j'\),選\(j\)就要選\(i'\)。故\(i\to j',j\to i'\)。一般操作即為\(a_i \operatorname{xor} a_j=1\)
- \(i,j\)必須同時選:選了\(i\)就要選\(j\),選\(j\)就要選\(i\)。故\(i\to j,j\to i\)。一般操作即為\(a_i \operatorname{xor} a_j=0\)
- \(i,j\)任選(但至少選一個)選一個:選了\(i\)就要選\(j'\),選\(j\)就要選\(i'\),選\(i'\)就要選\(j\),選\(j'\)就要選\(i\)。故\(i\to j',j\to i',i'\to j,j'\to i\)。一般操作即為\(a_i \operatorname{or} a_j=1\)
- \(i\)必須選:直接\(i'\to i\),可以保證無論怎樣都選\(i\)。一般操作為給出的\(a_i=1\)或\(a_i \operatorname{and} a_j=1\)
建好圖然后就是考慮怎么用圖論的方式解決2-SAT了。
How to solve 2-SAT——DFS
- 對於每個當前不確定的變量\(a_i\),令\(a_i=0\)然后沿着邊DFS訪問相連的點。
- 檢查如果會導致任意一個\(j\)與\(j'\)都被選,那么撤銷。否則令\(a_i=0\)
- 否則令\(a_i=1\),重復2。如果還不行就無解。
- 繼續考慮下一個不確定的變量
這樣的話正確性顯然,由於這里的DFS涉及到全局,因此復雜度是\(O(n(n+m))\)的。
一般情況下已經很優秀了,而且還可以改進:
只需要在DFS之前判斷\(i'\)能否走到\(i\)就可以省略撤銷標記的過程,所以我們可以bitset優化傳遞閉包做到\(O(\frac{n^3}{w})\)預處理,然后就可以\(O(n+m)\)的DFS了。
這種做法還可以保證解的字典序,有時不失為一種不錯的方法。
How to solve 2-SAT——SCC
考慮我們上面的判斷有無解的情況,我們想到完全可以借助SCC來判斷兩個點是否互相到達。
那么我們先縮點,如果\(i\)與\(i'\)在同一SCC里那么顯然無解。
否則選擇\(i\)與\(i'\)中拓撲序較大的一個就可以得到一組可行解。
不是很常用(主要是一般題目的數據范圍都不需要),用來判可行性比較好。
兩道例題
- HDU 3062Party 2-SAT建圖后判斷可行性即可。
- HDU 1814Peaceful Commission 2-SAT建圖后求字典序最小解,就用DFS的方法不預處理也可以過。
Postscript
這真的是一篇超入門博客,沒有涉及特別多的難點以及姿勢。
像數據結構優化建圖我是肯定不會的啦,最后推薦一道比較有難度的2-SAT好題:Luogu P3825 [NOI2017]游戲&&Sol
