學習筆記 2 SAT 小結

2022-06-02 03:06:06 字數 2113 閱讀 9492

目錄從sat說起

布林可滿足性問題(boolean satisfiability problem;sat))屬於決定性問題,也是第乙個被證明屬於np完全的問題。 此問題在電腦科學上許多領域的皆相當重要,包括電腦科學基礎理論、演算法、人工智慧、硬體設計等等。---摘自某百科

如:有三個bool變數,三個人要求的取值如下

a:101

b:110

c:111

如果三個人要被滿足至少乙個取值,求方案。

雖然sat是np完全問題,不過今天介紹的\(2-sat\)是特殊的,其可以在\(o(n+m)\)的時間完成。

前置知識:tarjan(強聯通分量),一定的邏輯思維

部分定義:

取值:本文中乙個變數的取值有且只有\(0\)和\(1\),即\(bool\)變數

\(tarjan\)編號:指求強聯通分量時,求出的強聯通分量編號。

熱身請注意:這裡的或指的是邏輯或,即兩者至少滿足一條,而非二選一。

顯然,我們可以得出

1:如果a選0,則b必須選1

2:如果b選1,則a必須選1

這個留給讀者自行思考

建邊我們可以通過建邊將其表達出來。\((u,v)\)的意義是,假設選擇了\(u\),則必須選\(v\)。那麼我們就可以按照上面所述進行建邊。

我們將每個變數拆成兩點,對於\(1 \le i \le n\),\(i\)的意義是第\(i\)個變數選\(0\),\(i+n\)為選\(1\)。

那麼,我們就得到一張完整的有向圖了。

我們可以發現:對於乙個環,只要選定乙個點,那麼其他點也隨之確定。所以,我們可以通過強聯通分量,使其成為一張有向無環圖!

求解假設\(i\)與\(i+n\)在同乙個強聯通分量內,則表示「假設第\(i\)個變數選0,那麼就要選\(1\)」(或反過來),這時一定無解。

(那麼此時上面的謎底也出來了,如果\(i\)必須為\(0\),則建邊\((i+n,i)\),如果必須選\(i=1\),則無解)

那麼我們怎麼輸出解呢?

這時候我們請出拓撲序。如果對於兩個點\(u,v\),假設\(u\)的拓撲序小於\(v\),那麼沒有\(v\)沒有到\(u\)的路徑。證明略。

所以,假設對於\(i\),選拓撲序小的可能會出問題,所以應選拓撲序大的

q:拓撲好麻煩啊,能否不拓撲啊qwq

a:可以!考慮直接使用\(tarjan\)尋強聯通分量時留下來的編號,因為\(tarjan\)尋環是\(dfs\)下去的,與拓撲恰恰相反,所以,我們應選\(tarjan\)編號小的

q:講了這麼多,上**吧~

**

題目鏈結

這題只有乙個約束,即「或」約束,按上文所寫即可。

#includeusing namespace std;

int ltk,cc,to[2000500],net[2000500],fr[2005000],dfn[2000500],low[2005000],snack[2005000],color[2005000];

int df,p,u,v,u1,v1,n,m;bool vis[2000500];

void addedge(int u,int v)

void tarjan(int x)

else

if (vis[y]) low[x]=min(low[x],dfn[y]);

}if (dfn[x]==low[x])

color[x]=ltk;vis[snack[p]]=false;

p--;

}}//tarjan

int main()

for (int i =1;i<=2*n;i++)

for (int i=1;i<=n;i++)

}cout<<"possible\n";

for (int i=1;i<=n;i++)

else

}return 0;

}

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完之後沒有判為無解,那麼以...