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
",i+1) ;
        else 
            printf("%d
",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
", i + 1);} else puts("NIE");
    }
    return 0;
}
View Code
原文地址:https://www.cnblogs.com/xiaohongmao/p/3714218.html