1. 程式人生 > 其它 >圖論專題-學習筆記:2 - SAT 問題

圖論專題-學習筆記:2 - SAT 問題

@

目錄

一些 update

update 2021/11/12:修正了文章中的一些語言。

1. 前言

本篇文章將會對 2 - SAT 問題做一個講解。

前置知識:強連通分量/縮點(我的部落格連結/強連通分量 - OI Wiki)。

2. 詳解

首先我們需要知道 2 - SAT 是什麼。

實際上 2 - SAT 是 k - SAT 的一種特殊情況。

k - SAT 問題的一般描述就是有一些物品,每個物品均有 \(k\) 個狀態,給出一些限制條件,諸如 A 為 a 狀態則 B 為 b 狀態之類的,問有無可行解,有時還會讓你求解。

目前 k - SAT 問題(\(k > 2\)

)已經被證明無多項式解法,只能暴力求解,但是 2 - SAT 因為其優良的性質使得當我們只需要任意一組解或者是判有無解的時候,可以採用 \(O(n + m)\) 演算法解決。

2 - SAT 一般描述如下:

現給出 \(n\) 個布林型別的值,可真可假,有 \(m\) 種限制條件,限制條件是如下 3 種情況之一:

  • \(A = p\),則 \(B = q\)
  • \(A = p\)\(B = q\) 至少有一個成立。
  • A 必須為 \(p\)

剩餘別的所有情況都可以轉化為上述三種情況。

現給出這些限制條件,問你有沒有一組取值,使得這組取值能夠滿足所有限制條件,如果有還需要求出一組可行解。

解決 2 - SAT 問題的方案一般是建圖。

對於每一個變數 \(x\) 我們建兩個點 \(x_0,x_1\),分別表示變數 \(x\) 取 0 或者取 1。

  • \(A = p\),則 \(B = q\)

為了方便,只討論若 \(A = 1\),則 \(B = 1\),其餘情況可以類推。

考慮連邊 \(A_1 \to B_1,B_0 \to A_0\),這麼連邊的意義是如果 \(A = 1\),那麼根據連邊可以推出 \(B = 1\),如果 \(B = 0\),那麼根據連邊可以推出 \(A = 0\)

注意 \(B_0 \to A_0\) 正確性是因為原命題的逆否命題正確。

  • \(A = p\)
    \(B = q\) 至少有一個成立。

為了方便,只討論 \(A = 1\)\(B = 1\) 至少有一個成立,其餘情況可以類推。

考慮連邊 \(A_0 \to B_1,B_0 \to A_1\),意義是如果 \(A = 0\)\(B = 1\) 必然成立,同理 \(B = 0\)\(A = 1\) 必然成立。

  • A 必須為 \(p\)

為了方便,只討論 \(A = 1\) 的情況,其餘情況可以類推。

對於這種情況,直接連邊 \(A_0 \to A_1\),意義是如果 \(A = 0\),根據連邊可以發現 \(A = 1\),這意味著 \(A \ne 0\),只能是 \(A = 1\),該連邊可以控制 \(A \ne 0\)

這麼操作之後,我們得到了一張有向圖,其中的有向邊表示推出關係。

那麼接下來如何判斷有無解呢?

採用強連通分量演算法。

假設說某變數 \(x\),其兩個點 \(x_0,x_1\) 處於同一個強連通分量中,這說明從 \(x = 0\) 出發能夠推出 \(x = 1\),從 \(x = 1\) 出發能夠推出 \(x = 0\),因此 \(x \ne 0,x \ne 1\),這樣就無解了。

那麼如何求出一組可行解呢?

首先對這一張圖縮點,然後我們就得到了一張 DAG。

如果 \(x_0\) 處於強連通分量 \(A\) 中,\(x_1\) 處於強連通分量 \(B\) 中,且 \(A\) 的拓撲序小於 \(B\),那麼有兩種可能:

  • \(x_0,x_1\) 互不干擾。
  • \(x_0\) 能夠推出 \(x_1\)

發現無論哪種情況選擇 \(x_1\) 都是正確的,因此對於變數 \(x\) 而言,\(x_0,x_1\) 哪個拓撲序大選哪個能夠保證選出來的解是正確的。

所以我們需要對建出來的圖縮點,然後跑拓撲排序,求出拓撲序,然後求解……

嗎?

不需要!在求強連通分量的時候我們已經得到拓撲序了。

若採用 Kosaraju 演算法(兩遍 dfs):

求強連通分量的時候我們會得到一個 Color[] 陣列表示其屬於的強連通分量的編號,而根據 Color[] 陣列可以直接推出兩個強連通分量的拓撲序大小:

  • 對於縮點之後的圖上的兩個點 \(i,j\),如果 \(Color_i < Color_j\),則 \(i\) 一定能夠走到 \(j\)。換言之,求出這張圖的拓撲序後 \(i\)\(j\) 前面。

上述結論的證明過程我在我的文章圖論專題-學習筆記:強連通分量中證明過,此處不再證明,想了解的讀者可以進入我的文章瞭解。

實質上 Color[] 就是新圖的拓撲序(之一)。

若採用 Tarjan 演算法:

採用 Tarjan 演算法需要注意的一點就是求出的 scc[] 陣列是反過來的,也就是說 scc[] 越大其拓撲序越小,這點跟 Kosaraju 演算法是不一樣的,也比較容易出錯。

證明的話實際上是因為 Tarjan 求強連通分量的時候我們是倒著標記強連通分量的,因此拓撲序最小的強連通分量其標號是最大的。

我更推薦 Kosaraju 演算法~

洛谷模板題:P4782 【模板】2-SAT 問題

洛谷的模板題只有情況 2。

Code:GitHub CodeBase-of-Plozia P4782 【模板】2-SAT 問題.cpp

3. 總結

2 - SAT 問題的一般解法是根據邏輯關係進行拆點連邊,然後求強連通分量判斷有無解以及求出一組解。