HDU 3062 Party (2-SAT模板题)

2-SAT问题:

有N个值为0或1的元素,给定一些包含两元素限制条件(子句),如选择某元素则不能选某元素,或选择某元素则必须选某元素,问是否能给所有变量一组赋值使满足所有限制。


解法:

把所有的a,~a都当作节点。如果a,b互斥,则连边(a,~b)和(b,~a),然后用Tarjan求一下强联通分量,若任意a,~a在一个联通分量中,则无解,否则有解。


代码:

#include <iostream>
#include <cstdio>
#define LL long long
#include <cstring>
using namespace std;
#include <map>
#include <queue>
#include <algorithm>
#define maxn 2000
#define maxe 1000000
int N,M;

int dfn[maxn],low[maxn],belong[maxn],num,dep;
int inStack[maxn],Stack[maxn],top;
void minimize(int &a,int &b){
    if(b<a) a=b;
}


struct Arclist{
    struct Edge{int v,next;}E[maxe];
    int head[maxn],cur;
    void add(int u,int v){E[cur].v=v; E[cur].next=head[u]; head[u]=cur++;}
    void init(int n=maxn){
        cur=0;
        top=0; num=0;
        memset(head,-1,sizeof(head));
        memset(dfn,0,sizeof(dfn));
    };
    void Tarjan(int u){
        low[u]=dfn[u]=++dep;
        Stack[top++]=u; inStack[u]=1;
        for(int p=head[u];~p;p=E[p].next){
            int v=E[p].v;
            if(!dfn[v]){Tarjan(v); minimize(low[u],low[v]); }
            else if(inStack[v]) minimize(low[u],dfn[v]);
        }
        if(dfn[u]==low[u]){
            belong[u]=++num; inStack[u]=0;
            for(int t=Stack[--top]; t!=u; t=Stack[--top]){
                inStack[t]=0;
                belong[t]=num;
            }
        }
    }
    bool solve(int n){
        int maxN=n*2;
        for(int i=0;i<maxN;i++){
            if(!dfn[i]) Tarjan(i);
        }
        for(int i=0;i<maxN;i++){
            if(belong[i]==belong[i^1])
                return 0;
        }
        return 1;
    }
}G1;

int main(){
    while(~scanf("%d",&N)){
        scanf("%d",&M);
        G1.init();
        for(int i=0;i<M;i++){
            int a1,a2,c1,c2;
            scanf("%d%d%d%d",&a1,&a2,&c1,&c2);
            a1*=2;if(c1) a1++;
            a2*=2;if(c2) a2++;
            G1.add(a1,a2^1);
            G1.add(a2,a1^1);
        }

        if(G1.solve(N)) printf("YES\n");
        else printf("NO\n");
    }
    return 0;
}



你可能感兴趣的:(2-sat)