2 SAT學習筆記

2022-09-20 09:57:10 字數 1164 閱讀 8462

給定一串布林變數,每個變數只能為真或假。要求對這些變數進行賦值,滿足布林方程。這就是2-sat問題。

我們發現每塊點都有兩種狀態(真、假),於是我們可以想到將點 \(u\)​​ 拆分成 \(u0,u1\)​ ,分別表示 \(u\)​ 點為假、真。我們若連的邊為 \(u \to v\) ,就表示選擇 \(u\) 就必須選 \(v\) 。

如果題目給出了一種條件 \(a \and b = true\)​​ ,那麼我們就連一條 \(a1 \to b1\)​​ 的邊。

連邊方法:

\(a \and b = true \rightarrow (a1,b1),(b1,a1)\)

\(a \and b = false \rightarrow (a1,b0),(b1,a0)\)​

\(a \or b = true \rightarrow (a0,b1),(b0,a1)\)​​

\(a \or b = false \rightarrow (a0,b0),(b0,a0)\)​​

由所構造的狀態可知,對於圖中的每乙個強連通分量,如果選擇了其中任意乙個點,那就意味著這個強連通分量中的所有點都要選。顯然 \(x0,x1\)​​ 不可以同時選,由此可以判斷有無解。

由連邊的方式可以得知,我們對於每個點的兩種狀態,選擇拓撲序大的,捨棄掉另乙個。

小技巧:這裡可以不用再搞一遍拓撲排序,因為 \(tarjan\)​ 求強連通分量每個點所在的強連通分量編號可以代替拓撲序。

如果要求字典序最小呢?用dfs列舉點 \(1 \to 2n\) ,如果這個點可以選,那就將與其相連的點都選上。如果發生衝突,就取消選擇這個點以及與其相連的點。

模板題,可以結合**感性理解。

**:

#include #include #include #define min(a,b) ((a)<(b)?(a):(b))

using namespace std;

const int n=2e6+7;

vectoredge[n];

stacksta;

int dfn[n],low[n];

int leader[n]; // 所屬強連通分量編號

int n,m,deep,cnt;

inline void addedge(int u,int v)

inline void tarjan(int u)

2 SAT學習筆記

由對稱性解2 sat問題 2 sat解法 上面兩篇 很清楚的介紹了什麼是2 sat以及一些原理演算法 2 sat問題是圖論中乙個比較有意思的問題,重點是建圖,對於邊的意思,就是如果你選了i,就必須選j。2 sat問題有個很明顯的地方就是對於每個i,i包含兩個點,i表示選第乙個點,i 表示選第二個點,...

2 SAT學習筆記

2 sat問題指的是,給你若干個0 1變數。並給你一些限制,讓你求滿足這些限制的可行解 字典序最小的解 限制的種類包括以下幾種 1 a一定是1 2 a一定不是1 3 a,b至少有1個是1 4 a,b最多有乙個是1 5 a,b一定相同 6 a,b一定不同 一般思路是對於乙個變數,建立兩個變數 正,反 ...

2 sat學習筆記

例 struct twosat x xval or y yval void add clause int x,int xv,int y,int yv void init int n bool solve return1 為什麼不需要回溯呢?因為以前定下的變數如果在一輪dfs完之後沒有判為無解,那麼以...