2-SAT問題總結


2-SAT問題總結

       2-SAT問題:n個布爾型的變量,給出m個約束條件,約束條件例如:A,B不能同時為真,A,B必須同時為真等。

       看了算法入門經典中的解決辦法,關於這種解決辦法比較容易理解,並且效率也不錯。構造一張有向圖G,其中n個變量拆成n*2個變量,也就是xi用xi*2和xi*2+1表示,如果前者標記為1,那么說明xi為真,如果后者標記為1,那么說明xi為假。對於約束條件就可進行構成邊,例如xi為假或者xj為假,也就是xi為假xj必須為真,xj為假xi必須為真,這樣就得到兩條有向邊,xi*2+1 -> xj*2    xj*2+1 -> xi*2,這樣就得到了有向圖G。

       有向圖中所有的有向邊肯定組成了若干連通分量,某一連通分量中的,一點如果為1那么,這個連通分量中的所有點都要是1,反之也是,如果某一點既為1,又為0,那么m個約束條件肯定是產生矛盾了,那么這個問題就無法解決。

       模擬這個過程的時候用的是dfs,從一點開始我們先假設這個點為0,然后從這個點開始遍歷所有它能到達的點,都標記一下,如果標記過程中發現某點已經為1了,那么就以這個點為1再以這個點開始遍歷,如果這個點為1為0都會產生矛盾,那么就是出現了上面的問題,約束條件產生矛盾,問題無法得到解決。

/*********************************************2-SAT模板*********************************************/
const int maxn=10000+10;
struct TwoSAT
{
    int n;//原始圖的節點數(未翻倍)
    vector<int> G[maxn*2];//G[i].j表示如果mark[i]=true,那么mark[j]也要=true
    bool mark[maxn*2];//標記
    int S[maxn*2],c;//S和c用來記錄一次dfs遍歷的所有節點編號

    //從x執行dfs遍歷,途徑的所有點都標記
    //如果不能標記,那么返回false
    bool dfs(int x)
    {
        if(mark[x^1]) return false;//這兩句的位置不能調換
        if(mark[x]) return true;
        mark[x]=true;
        S[c++]=x;
        for(int i=0;i<G[x].size();i++)
            if(!dfs(G[x][i])) return false;
        return true;
    }
    
    void init(int n)
    {
        this->n=n;
        for(int i=0;i<2*n;i++) 
            G[i].clear();
        memset(mark,0,sizeof(mark));
    }

    //加入(x,xval)或(y,yval)條件
    //xval=0表示假,yval=1表示真
    void add_clause(int x,int xval,int y,int yval)//這個地方不是一塵不變的,而是參照問題的約束條件進行加邊
    {
        x=x*2+xval;
        y=y*2+yval;
        G[x^1].push_back(y);
        G[y^1].push_back(x);
    }

    //判斷當前2-SAT問題是否有解
    bool solve()
    {
        for(int i=0;i<2*n;i+=2)
        if(!mark[i] && !mark[i+1])
        {
            c=0;
            if(!dfs(i))
            {
                while(c>0) mark[S[--c]]=false;
                if(!dfs(i+1)) return false;
            }
        }
        return true;
    }
};
/*********************************************2-SAT模板*********************************************/

 

                                                                     


免責聲明!

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



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