DLX解決3-SAT問題

來源:互聯網
上載者:User

1.關於DLX的重複覆蓋:根據與精確覆蓋概念的區別可知,只需改變remove()和resume()函數控制刪除和恢複的過程即可實現,對於求解最少步數問題,可藉助ida*中的h()函數最佳化。

2.重複覆蓋+精確覆蓋:某些元素可重複覆蓋(目標),而某些元素只能精確覆蓋(每類元素只能使用一次),這是要對前m列進行重複覆蓋的刪除回複操作,對後面的列進行精確覆蓋的操作,也有一些特殊情況可直接使用重複覆蓋代替。如hdu2828,每類元素只有兩種,可通過visit數組在選中某個元素時刪除同類中的另一個元素,實現精確覆蓋)。

3.K-sat問題:

考慮CNF

Φ=C1∧C2∧...∧Ci∧...Cn


子句Ci具有如下形式

Xi1∨Xi2∨...∨Xij∨...∨Xili


Xij為命題變元集Xij為{x1,x2....xm}中的一個變元,其中Xij稱為本文字,Xij稱為負文字,子句Ci中文字的個數定義為子句的長度,用li表示。對於一個子句Ci,只要其中一個文字為真,則稱該子句是可滿足的。
一個判定形式的SAT問題是指:對於給定的CNF是否存在一組關於命題的變元的真值賦值使得為真。
特殊的,當每個子句的長度為K時,則成為K-SAT問題。

以3-SAT為例(xmu1101),有遺傳演算法和dlx兩種做法,這裡介紹後者。

問題:有n個元素,每個元素有選和不選兩種狀態,因此可以看做n*2中元素;m個約束,每個約束要求某3個元素中至少選一個。目標:能否從2*n個元素中選擇一些元素使其滿足所有約束。

建模:由於要是元素m種約束,因此把m種約束看做重複覆蓋的列,把2*n中元素看做行,如果第i個元素在第j個約束中,則mat[i][j]=1,同時每個元素只能有一種狀態,因此將n個元素作為精確覆蓋的列mat[i][m+i]=mat[i+n][m+i]=1,求解是否存在滿足條件的覆蓋即可,輸出方案也很簡單。

import java.util.Arrays;import java.util.Scanner;public class SAT_3 {class DLX {int maxn = 1010, inf = 1 << 28;int L[] = new int[maxn], R[] = new int[maxn], D[] = new int[maxn],U[] = new int[maxn];int Row[] = new int[maxn], C[] = new int[maxn], S[] = new int[maxn];// 元素x所在行列 每列元素個數int m, id, rowid;void init(int m) {this.m = m;for (int i = 0; i <= m; i++) {D[i] = U[i] = i;S[i] = 0;L[i] = i - 1;R[i] = i + 1;}L[0] = m;R[m] = 0;id = m + 1;rowid = 1;}void insert(int arr[], int len) {for (int i = 0; i < len; i++, id++) {int x = arr[i];C[id] = x;Row[id] = rowid;S[x]++;D[id] = x;U[id] = U[x];D[U[x]] = id;U[x] = id;if (i == 0)L[id] = R[id] = id;else {L[id] = id - 1;R[id] = id - i;L[id - i] = id;R[id - 1] = id;}}rowid++;}void remove(int c) {for (int i = U[c]; i != c; i = U[i]) {L[R[i]] = L[i];R[L[i]] = R[i];}}void resume(int c) {for (int i = D[c]; i != c; i = D[i]) {L[R[i]] = i;R[L[i]] = i;}}void ExRemove(int c) {L[R[c]] = L[c];R[L[c]] = R[c];for (int i = D[c]; i != c; i = D[i])for (int j = R[i]; j != i; j = R[j]) {S[C[j]]--;U[D[j]] = U[j];D[U[j]] = D[j];}}void ExResume(int c) {for (int i = U[c]; i != c; i = U[i])for (int j = L[i]; j != i; j = L[j]) {S[C[j]]++;U[D[j]] = j;D[U[j]] = j;}L[R[c]] = c;R[L[c]] = c;}boolean dance() {if (R[0] == 0 || R[0] > bound)return true;int c = R[0];for (int i = R[0]; i != 0; i = R[i])if (S[i] < S[c] && i <= bound)c = i;for (int i = D[c]; i != c; i = D[i]) {remove(i);int idx = -1;for (int j = R[i]; j != i; j = R[j]) {if (C[j] <= bound)remove(j);elseidx = j;}if (idx != -1)ExRemove(C[idx]); // C[]!!if (dance())return true;if (idx != -1)ExResume(C[idx]); // C[]!!for (int j = L[i]; j != i; j = L[j])if (C[j] <= bound)resume(j);resume(i);}return false;}int bound;void solve(int b) {this.bound = b;if (dance())System.out.println("Yes");elseSystem.out.println("No");}}DLX dlx=new DLX();Scanner scan=new Scanner(System.in);int cnf[][]=new int[110][210],len[]=new int[110];void run(){int n=scan.nextInt();int m=scan.nextInt();for(int i=1;i<=n;i++){cnf[i][0]=cnf[i+n][0]=m+i;len[i]=len[i+n]=1;}dlx.init(m+n);for(int i=1;i<=m;i++){for(int j=0;j<3;j++){int v=scan.nextInt();if(v<0)v=n-v;cnf[v][len[v]++]=i;}}for(int i=1;i<=n*2;i++)dlx.insert(cnf[i], len[i]);dlx.solve(m);}public static void main(String[] args) {new SAT_3().run();}}


聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.