淺談2-SAT(待續)


2-SAT問題,其實是一個邏輯互斥問題。
做了兩道裸題之后仔細想來,和小時候做過的“有兩個女生,如果A是女生,那么B一定不是女生。A和C性別相同,求A、B、C三人的性別。”幾乎是一樣的。

對於這道題我們來分析一下。
“如果A是女生,那么B一定不是女生”——A和B性別相反,假設“A為女生”為true,那么“B為女生”必定為false,於是一定有“B為男生”為true【注意是一定】。
對於這句話同理可得,假設“B為女生”為true,那么“A為男生”必定為true。
“A和C性別相同”——假設“A為女生”為true,那么“C為女生”必定為true; 假設“A為男生”為true,那么“C為男生”必定為true。
這道題的邏輯關系十分簡單,我們可以肉眼看出答案,然而對於一些邏輯關系成千上萬達到1E6數量的我們不能直觀看出,所以針對比較復雜的情況,人力想出了列表的方法。

      | A | B | C
——————————
女   |    |    |
——————————
男   |    |    |

之后對於隨機選擇一個格子進行假設保證不出現互斥的情況。

如何實現的?比如我在"A男"這一格打了勾,那么必定會在“B女”,“C男”打勾,發現不滿足題意,再令A為女生重新打勾。

 

下面討論2-SAT的算法。
先說一些概念:
一個命題:若P則Q。
它的逆否命題:若非Q則非P。
這兩個是等價的(大多2-SAT圖是對稱的,一些不對稱的圖指定了某個條件的真假性)

一些“不同時為真”、“不同時為假”的邏輯關系都可以化成“若P則Q”的形式(“不同時為真”:若A為真則B為假,及其逆否命題 若B為真則A為假;若B為假則A為真,及其逆否命題 若A為假則B為真)

對於“若P則Q”,我們從P出發,連一條邊到Q,代表P如果為真Q一定為真。對於所有這樣的邏輯關系都建立這樣的邏輯邊,之后選取一個節點進行假設賦值,如果這個點無論真假都不滿足條件,該問題就無解。

然后解題順序:
1.建圖(把每個點拆成點A 2*i 和點B2*i+1,對於每個點A和B必定有且僅有一個為真)
2.跑2-SAT

下面放代碼模板

 

 1 void _clean(){
 2 
 3     for(int i=2;i<=n*2+1;i++){
 4     g[i].clear();
 5     mark[i]=false;
 6     }
 7 }
 8 
 9 bool _dfs(int u){
10 
11     if(mark[u^1])return false;//如果該點的對立面為真,該點必定為假
12     if(mark[u])return true;//如果該點之前掃過,為真,那么直接返回
13     mark[u]=true;//如果這個點沒討論過(A/B兩點均沒賦值),那么把該點賦為真
14     stk[++top]=u;//進棧,這個我還沒能理解,不過最后滿棧應該是top==n,棧里的都為真
15     for(int i=0;i<g[u].size();i++)
16     if(!_dfs(g[u][i]))return false;//該點為真,那么和這個點相連的每個點全必須為真,否則返回false
17     return true;
18 }
19 
20 bool _Twosat(){
21     
22     _clean();
23     top=0;
24     for(int i=2;i<=n*2+1;i+=2)
25     if(!mark[i+1] && !mark[i]){//如果該點沒討論過
26         top=0;
27         if(!_dfs(i)){假設A點為真失敗
28         while(top)
29             mark[stk[top--]]=false;//棧里元素全出棧,並賦值為假
30         if(!_dfs(i+1))return false;//如果假設B點為真也失敗,那么無解。
31         }
32         }
33     return true;
34 }

 

 

補充:

1、2-SAT問題就是一個“不能同時為真”、“若滿足狀態1就必定滿足狀態2”的邏輯問題。這一類問題的特點大多是對於每個對象可以等價成兩種互斥狀態。

2、大多的2-SAT問題是對稱的,即滿足p->q,就一定滿足-q->-p(逆否命題的互推),但也有個別例外,就是比如有一個對象與2-sat圖的其他對象關聯,但是題目已經決定了這個對象必須是某一個狀態(不能自我假設了,這個時候可以對於這個點跑一個裸的dfs,一會兒我會講到例題)

 

下邊講幾道2-SAT的題目(都只講建圖不放代碼了)

1、

Now or laterUVALive - 3211 

另一篇博文里有詳細題解:http://www.cnblogs.com/L-Excalibur/p/8513386.html

 

2、

AstronautsUVALive - 3713

題目鏈接:https://cn.vjudge.net/contest/209473#problem/K

題目大意:有一堆宇航員要去完成任務,A任務非常偉大,只有能力值大於等於平均能力值的人才能完成,B任務是普通任務,只有能力值低於平均能力值的人才會去完成,C任務不限制條件,所有能力值的人都可以做。但是這堆宇航員互相有一些憎恨關系,如果兩個宇航員互相憎恨,那么就不能給他們分配同一個任務,給出一個合理方案,如果沒有合理方案輸出no solution。

解題思路:每個能力值大於等於平均值的人(以下簡稱第一類人)划分為兩種狀態a.選擇任務A,b.選擇任務C;能力值小於平均值(第二類人)划分為兩種狀態a.選擇任務B,b.選擇任務C。如果第一類人或第二類人有內部矛盾,那么如果其中一個為狀態a,另一個一定為狀態b(對稱建圖,不能同時為a和b,共四條)。如果第一類人和第二類人有矛盾,那么不能同時為b,一個為b另一個一定為a。

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM