本篇文章主要是根據上屆一個東大學長謝文豔寫的一篇《給定2CNF可滿足性問題》自己重新總結了一下,然後把所有的代碼都調試了一遍,不過有一點要注意的是,文章中的方法能夠判斷問題是有具有解,能給出該問題的一種可行解,但並不能給出所有的解。
我自己總結爲兩個部分,圖論問題和算法的詳解。
一、將問題轉換爲圖論問題
首先,將2CNF的問題轉換爲圖論問題。
下面的規則說明了如何把一個2CNF轉化爲一個有向圖G=<V,E>:
u 把2CNF的每個變量及這個變量的非都作爲圖G的頂點。顯然若這個2CNF有3個變量,那麼將有6個頂點。
u
第一步:首先爲那些有到自己的非的有向路徑的變量賦值,即如果圖G中有從x到的有向路徑,那麼將變量x賦值爲false。如果圖G中有從到x的有向路徑,則將變量x賦值爲true。將在這個步驟中被賦了值的變量稱爲一級變量。
如下所示:
第二步:依次從與每一個一級變量對應的節點出發(如果一級變量x被賦值爲true,則從與x對應的節點出發;如果x被賦值爲false, 則從與對應的節點出發),將所有能到達的、還沒有被賦值的節點賦值爲true(如果該節點對應於y,則將y賦值爲true;如果該節點對應於,則將y賦值爲false)。將在這個步驟中被賦了值的變量稱爲二級變量。
如下所示:
第三步:依次檢查還沒有被賦值的變量,如s,如果與s對應的頂點出度不爲0(有指向其它節點的有向邊),則將s賦值爲true,然後從與s對應的頂點出發,將所有能到達的、還沒有被賦值的節點賦值爲true;如果與s對應的頂點出度爲0,則將s賦值爲false,從與s對應的頂點出發,將所有能到達的、還沒有被賦值的節點賦值爲true。將在這個步驟中被賦了值的變量稱爲三級變量。
如下所示:
二、算法的詳解
1. 先構圖,並將圖表示爲鄰接矩陣。思想主要是將每一個字句用鄰接矩陣edges表示,如字句xUy,輸入的時候表示爲:1 1。然後,將該字句表示 在數據結構中表示爲edges[n+1][2]=1以及edges[2][n+1]=1
2. 並找出一級變量。主要思想是調用isSatisfiable函數,利用廣度優先從頂點i到頂點n+i看看是否能走通,同時,也判斷從頂點n+i到頂點i,如果都走通了,說明誤解,否則判定這n個點後,不存在兩個條件都滿足的情況,則表示有解了。同時,在判斷的過程中,找出一級變量。
3. 找出二級變量和三級變量。從每一個一級變量出發,根據原則,利用廣度優先的算法,把所有能達到的變量變爲true,這些變量就是二級變量了。然後再獲取三級變量,通過一個循環,將沒有訪問過的變量,利用的原則來將所有的所能達到的置爲true。
4. 自此,算法結束,輸出所有變量的值。(注意:該算法只能獲得一組可行解,但不能獲得所有的解)
如果輸入:
格式如下:
4 3//第一個參數是行數 第二個是變量個數
//記下來是字句輸入 如表示爲-1 2
-1 2
-2 3
1 -3
3 2
得出結果:
有可行解
1:1
2:1
3:1
又例如輸入:
得出結果:
1:1 //X1:1
2:0 //x2:0
3:0 //x3:0
4:1 //x4:1
5:0 //x5:0
若有問題歡迎發郵件給我:[email protected]