2-sat

http://blog.sina.com.cn/s/blog_64675f540100k2xj.html

http://www.cppblog.com/MatoNo1/archive/2011/07/13/150766.aspx

讲解看的这两篇博客,其实最好直接去看国家集训队的论文,别的抄来抄去想找个原始出处都难,不过我也没什么原则说这话就对了。。

求出强连通分量后进行缩点,新图是dag图,具有拓扑性质,直接在上面进行染色

http://acm.hdu.edu.cn/showproblem.php?pid=3062

2-sat判定性,复杂度O(M)

#include <iostream>

#include <algorithm>

#include <cstring>

#include <cstdio>

#include <queue>

#include <map>

using namespace std ;

struct node 

{

    int s,t,nxt ;

}e[4000005] ;

int n,m,idx,ans,tp,cnt,dfn[100005],vis[100005],low[100005],head[100005],st[100005],belong[100005] ;

void add(int s,int t)

{

    e[cnt].s=s ;

    e[cnt].t=t ;

    e[cnt].nxt=head[s] ;

    head[s]=cnt++ ;

}

void tarjan(int u)

{

    dfn[u]=low[u]=++idx ;

    vis[u]=1 ;

    st[++tp]=u ;

    int v ;

    for(int i=head[u] ;i!=-1 ;i=e[i].nxt)

    {

        v=e[i].t ;

        if(!dfn[v])

        {

            tarjan(v) ;

            low[u]=min(low[u],low[v]) ;

        }

        else if(vis[v])

            low[u]=min(low[u],dfn[v]) ;

    }

    if(dfn[u]==low[u])

    {

        ans++ ;

        while(1)

        {

            v=st[tp--] ;

            vis[v]=0 ;

            belong[v]=ans ;

            if(v==u)break ;

        }

    }

}

bool _2sat()

{

    memset(vis,0,sizeof(vis)) ;

    memset(dfn,0,sizeof(dfn)) ;

    idx=tp=ans=0 ;

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

        if(!dfn[i])

            tarjan(i) ;

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

        if(belong[2*i]==belong[(2*i)^1])

            return false ;

    return true ;

}

int main()

{

    while(~scanf("%d%d",&n,&m))

    {

        cnt=0 ;

        memset(head,-1,sizeof(head)) ;

        while(m--)

        {

            int a,b,c,d ;

            scanf("%d%d%d%d",&a,&b,&c,&d) ;

            int u,v ;

            u=a*2+c ;v=b*2+d ;

            add(u,v^1) ;add(v,u^1) ; 

        }

        if(_2sat())puts("YES") ;

        else puts("NO") ;

    }

    return 0 ;

}
View Code

http://acm.hit.edu.cn/hoj/problem/view?id=1917

2-sat判定性,且能输出任意一组解,解法见赵爽的集训队论文,复杂度O(M)

#include <iostream>

#include <algorithm>

#include <cstring>

#include <cstdio>

#include <queue>

#include <map>

using namespace std ;

struct node 

{

    int s,t,nxt ;

}e[400005],dag[400005] ;

int n,m,idx,ans,tp,cnt,dfn[100005],vis[100005],low[100005],head[100005],st[100005],belong[100005] ;

void add(int s,int t)

{

    e[cnt].s=s ;e[cnt].t=t ;e[cnt].nxt=head[s] ;head[s]=cnt++ ;

}

int cntdag,headdag[100005] ;

void adddag(int s,int t)

{

    dag[cnt].s=s ;dag[cnt].t=t ;dag[cnt].nxt=head[s] ;headdag[s]=cntdag++ ;

}

void tarjan(int u)

{

    dfn[u]=low[u]=++idx ;

    vis[u]=1 ;

    st[++tp]=u ;

    int v ;

    for(int i=head[u] ;i!=-1 ;i=e[i].nxt)

    {

        v=e[i].t ;

        if(!dfn[v])

        {

            tarjan(v) ;

            low[u]=min(low[u],low[v]) ;

        }

        else if(vis[v])

            low[u]=min(low[u],dfn[v]) ;

    }

    if(dfn[u]==low[u])

    {

        ans++ ;

        while(1)

        {

            v=st[tp--] ;

            vis[v]=0 ;

            belong[v]=ans ;

            if(v==u)break ;

        }

    }

}

void builddag()

{

    cntdag=0 ;

    memset(headdag,-1,sizeof(headdag)) ;

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

    {

        for(int j=headdag[i] ;j!=-1 ;j=dag[j].nxt)

        {

            int v=e[j].t ;

            if(belong[v]!=belong[i])//缩点 

                adddag(belong[v],belong[i]) ;//建立反向边

        }

    }

}

int color[100005],cp[100005] ;

void bfs()//染色 

{

    memset(color,0,sizeof(color)) ;

    queue <int> q ;

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

        q.push(i) ;

    while(!q.empty())

    {

        int u=q.front() ;

        q.pop() ;

        if(!color[u])

        {

            color[u]=1 ;

            color[cp[u]]=-1 ; 

        }

        for(int i=headdag[u] ;i!=-1 ;i=dag[i].nxt)

        {

            int v=dag[i].t ;

            q.push(v) ;

        }

    } 

}

void _2sat()

{

    memset(vis,0,sizeof(vis)) ;

    memset(dfn,0,sizeof(dfn)) ;

    idx=tp=ans=0 ;

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

        if(!dfn[i])

            tarjan(i) ;

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

    {

        if(belong[2*i]==belong[(2*i)^1])

        {

            puts("NIE") ;

            return ;

        }

        else

        {

            cp[belong[i*2]]=belong[(i*2)^1] ;

            cp[belong[(i*2)^1]]=belong[i*2] ;

        }

    }

    builddag() ;

    bfs() ;

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

    {

        if(color[belong[i]]==1)

            printf("%d\n",i+1) ;

        else 

            printf("%d\n",i+2) ;

    }

    return ;

}

int main()

{

    while(~scanf("%d%d",&n,&m))

    {

        cnt=0 ;

        memset(head,-1,sizeof(head)) ;

        while(m--)

        {

            int a,b ;

            scanf("%d%d",&a,&b) ;

            a-- ;b-- ;

            add(a,b^1) ;add(b,a^1) ; 

        }

        _2sat() ;

    }

    return 0 ;

}
View Code

http://acm.hdu.edu.cn/showproblem.php?pid=1814

2-sat判定且能输出字典序最小的一组解,复杂度O(NM)

不过这个做法我还没看,已经快吐了,先放到这里不管 

#include <iostream>

#include <stdio.h>

using namespace std;

#define re(i, n) for (int i=0; i<n; i++)

const int MAXN = 20000, MAXM = 100000, INF = ~0U >> 2;

struct node {

    int a, b, pre, next;

} E[MAXM], E2[MAXM];

int _n, n, m, V[MAXN], ST[MAXN][2], Q[MAXN], Q2[MAXN], vst[MAXN];

bool res_ex;

void init_d()

{

    re(i, n) E[i].a = E[i].pre = E[i].next = E2[i].a = E2[i].pre = E2[i].next = i;

    m = n;

}

void add_edge(int a, int b)

{

    E[m].a = a; E[m].b = b; E[m].pre = E[a].pre; E[m].next = a; E[a].pre = m; E[E[m].pre].next = m;

    E2[m].a = b; E2[m].b = a; E2[m].pre = E2[b].pre; E2[m].next = b; E2[b].pre = m; E2[E2[m].pre].next = m++;

}

void solve()

{

    re(i, n) {V[i] = 0; vst[i] = 0;} res_ex = 1;

    int i, i1, i2, j, k, len, front, rear, front2, rear2;

    bool ff;

    re(_i, _n) {

        if (V[_i << 1] == 1 || V[(_i << 1) + 1] == 1) continue;

        i = _i << 1; len = 0;

        if (!V[i]) {

            ST[len][0] = i; ST[len++][1] = 1; if (!V[i ^ 1]) {ST[len][0] = i ^ 1; ST[len++][1] = 2;}

            Q[front = rear = 0] = i; vst[i] = i1 = n + i; Q2[front2 = rear2 = 0] = i ^ 1; vst[i ^ 1] = i2 = (n << 1) + i; ff = 1;

            for (; front<=rear; front++) {

                j = Q[front];

                for (int p = E[j].next; p != j; p=E[p].next) {

                    k = E[p].b;

                    if (V[k] == 2 || vst[k] == i2 || V[k ^ 1] == 1 || vst[k ^ 1] == i1) {ff = 0; break;}

                    if (vst[k] != i1) {

                        Q[++rear] = k; vst[k] = i1;

                        if (!V[k]) {ST[len][0] = k; ST[len++][1] = 1;}

                    }

                    if (vst[k ^ 1] != i2) {

                        Q2[++rear2] = k ^ 1; vst[k ^ 1] = i2;

                        if (!V[k]) {ST[len][0] = k ^ 1; ST[len++][1] = 2;}

                    }

                }

                if (!ff) break;

            }

            if (ff) {

                for (; front2<=rear2; front2++) {

                    j = Q2[front2];

                    for (int p = E2[j].next; p != j; p=E2[p].next) {

                        k = E2[p].b;

                        if (V[k] == 1 || vst[k] == i1) {ff = 0; break;}

                        if (vst[k] != i2) {

                            vst[k] = i2; Q2[++rear] = k;

                            if (!V[k]) {ST[len][0] = k; ST[len++][1] = 2;}

                        }

                    }

                    if (!ff) break;

                }

                if (ff) {

                    re(j, len) V[ST[j][0]] = ST[j][1];

                    continue;

                }

            }

        }

        i = (_i << 1) + 1; len = 0;

        if (!V[i]) {

            ST[len][0] = i; ST[len++][1] = 1; if (!V[i ^ 1]) {ST[len][0] = i ^ 1; ST[len++][1] = 2;}

            Q[front = rear = 0] = i; vst[i] = i1 = n + i; Q2[front2 = rear2 = 0] = i ^ 1; vst[i ^ 1] = i2 = (n << 1) + i; ff = 1;

            for (; front<=rear; front++) {

                j = Q[front];

                for (int p = E[j].next; p != j; p=E[p].next) {

                    k = E[p].b;

                    if (V[k] == 2 || vst[k] == i2 || V[k ^ 1] == 1 || vst[k ^ 1] == i1) {ff = 0; break;}

                    if (vst[k] != i1) {

                        Q[++rear] = k; vst[k] = i1;

                        if (!V[k]) {ST[len][0] = k; ST[len++][1] = 1;}

                    }

                    if (vst[k ^ 1] != i2) {

                        Q2[++rear2] = k ^ 1; vst[k ^ 1] = i2;

                        if (!V[k]) {ST[len][0] = k ^ 1; ST[len++][1] = 2;}

                    }

                }

                if (!ff) break;

            }

            if (ff) {

                for (; front2<=rear2; front2++) {

                    j = Q2[front2];

                    for (int p = E2[j].next; p != j; p=E2[p].next) {

                        k = E2[p].b;

                        if (V[k] == 1 || vst[k] == i1) {ff = 0; break;}

                        if (vst[k] != i2) {

                            vst[k] = i2; Q2[++rear] = k;

                            if (!V[k]) {ST[len][0] = k; ST[len++][1] = 2;}

                        }

                    }

                    if (!ff) break;

                }

                if (ff) {

                    re(j, len) V[ST[j][0]] = ST[j][1];

                    continue;

                }

            }

        }

        if (V[_i << 1] + V[(_i << 1) + 1] != 3) {res_ex = 0; break;}

    }

}

int main()

{

    int _m, a, b;

    while (scanf("%d%d", &_n, &_m) != EOF) {

        n = _n << 1; init_d();

        re(i, _m) {

            scanf("%d%d", &a, &b); a--; b--;

            if (a != (b ^ 1)) {add_edge(a, b ^ 1); add_edge(b, a ^ 1);}

        }

        solve();

        if (res_ex) {re(i, n) if (V[i] == 1) printf("%d\n", i + 1);} else puts("NIE");

    }

    return 0;

}
View Code

 

你可能感兴趣的:(SA)