演算法學習筆記 2 SAT

2022-01-10 08:07:32 字數 2647 閱讀 8302

sat 是適定性(satisfiability)問題的簡稱。一般形式為 k - 適定性問題,簡稱 k-sat。而當 \(k>2\) 時該問題為 np 完全的。所以我們只研究 \(k=2\) 的情況。

2-sat,簡單的說就是給出 \(n\) 個集合,每個集合有兩個元素,已知若干個 \(\) ,表示 \(a\) 與 \(b\) 矛盾(其中 \(a\) 與 \(b\) 屬於不同的集合)。然後從每個集合選擇乙個元素,判斷能否一共選 \(n\) 個兩兩不矛盾的元素。顯然可能有多種選擇方案,一般題中只需要求出一種即可。

比如邀請人來吃喜酒,夫妻二人必須去乙個,然而某些人之間有矛盾(比如 a 先生與 b 女士有矛盾,c 女士不想和 d 先生在一起),那麼我們要確定能否避免來人之間沒有矛盾,有時需要方案。這是一類生活中常見的問題。

使用布林方程表示上述問題。設 \(a\) 表示 a 先生去參加,那麼 b 女士就不能參加( \(\neg a\) ); \(b\) 表示 c 女士參加,那麼 \(\neg b\) 也一定成立(d 先生不參加)。總結一下,即 \((a \vee b)\) (變數 \(a, b\) 至少滿足乙個)。對這些變數關係建有向圖,則有: \(\neg a\rightarrow b\wedge\neg b\rightarrow a\) ( \(a\) 不成立則 \(b\) 一定成立;同理, \(b\) 不成立則 \(a\) 一定成立)。建圖之後,我們就可以使用縮點演算法來求解 2-sat 問題了。

演算法考究在建圖這點,我們舉個例子來講:

假設有 \(\) 和 \(\) 兩對,已知 \(a1\) 和 \(b2\) 間有矛盾,於是為了方案自洽,由於兩者中必須選乙個,所以我們就要拉兩條條有向邊 \((a1,b1)\) 和 \((b2,a2)\) 表示選了 \(a1\) 則必須選 \(b1\) ,選了 \(b2\) 則必須選 \(a2\) 才能夠自洽。

然後通過這樣子建邊我們跑一遍 tarjan scc 判斷是否有乙個集合中的兩個元素在同乙個 scc 中,若有則輸出不可能,否則輸出方案。構造方案只需要把幾個不矛盾的 scc 拼起來就好了。

輸出方案時可以通過變數在圖中的拓撲序確定該變數的取值。如果變數 \(\neg x\) 的拓撲序在 \(x\) 之後,那麼取 \(x\) 值為真。應用到 tarjan 演算法的縮點,即 \(x\) 所在 scc 編號在 \(\neg x\) 之前時,取 \(x\) 為真。因為 tarjan 演算法求強連通分量時使用了棧,所以 tarjan 求得的 scc 編號相當於反拓撲序。

顯然地,時間複雜度為 \(o(n+m)\) 。

就是沿著圖上一條路徑,如果乙個點被選擇了,那麼這條路徑以後的點都將被選擇,那麼,出現不可行的情況就是,存在乙個集合中兩者都被選擇了。

那麼,我們只需要列舉一下就可以了,資料不大,答案總是可以出來的。

爆搜模板

下方**來自劉汝佳的白書:

struct twosat

void init(int n)

void add_clause(int x, int y)

bool solve()

}return true;

}};

題面:有 n 對夫妻被邀請參加乙個聚會,因為場地的問題,每對夫妻中只有 \(1\) 人可以列席。在 \(2n\) 個人中,某些人之間有著很大的矛盾(當然夫妻之間是沒有矛盾的),有矛盾的 \(2\) 個人是不會同時出現在聚會上的。有沒有可能會有 \(n\) 個人同時列席?

這是一道多校題,裸的 2-sat 判斷是否有方案,按照我們上面的分析,如果 \(a1\) 中的丈夫和 \(a2\) 中的妻子不合,我們就把 \(a1\) 中的丈夫和 \(a2\) 中的丈夫連邊,把 \(a2\) 中的妻子和 \(a1\) 中的妻子連邊,然後縮點染色判斷即可。

#include#define maxn 2018

#define maxm 4000400

using namespace std;

int index, instack[maxn], dfn[maxn], low[maxn];

int tot, color[maxn];

int numedge, head[maxn];

struct edge edge[maxm];

int sta[maxn], top;

int n, m;

void add(int x, int y)

void tarjan(int x) else if (instack[v])

low[x] = min(low[x], dfn[v]);

} if (dfn[x] == low[x]) while (sta[top--] != x);

}}bool solve()

void init()

int main()

if (solve())

printf("yes\n");

else

printf("no\n");

} return 0;

}

hdu1814 和平委員會

poj3683 牧師忙碌日

文章開源在 github - blog-articles,點選 watch 即可訂閱本部落格。 若文章有錯誤,請在 issues 中提出,我會及時回覆,謝謝。

如果您覺得文章不錯,或者在生活和工作中幫助到了您,不妨給個 star,謝謝。

(文章完)

2 SAT演算法學習筆記

好像大概是這麼乙個東西,有一些集合,每個集合中有兩個元素 a i,bi ai bi 然後要求你從每乙個集合中選出乙個元素,但是同時對於集合元素的選取是有一些限制的,比如說什麼選了ai a i和aj a j必須選乙個,或者選了ai a i就必須選bj b j之類的。然後我們發現上面所有的限制條件都可以...

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一定不同 一般思路是對於乙個變數,建立兩個變數 正,反 ...