poj 3678 2-SAT问题
思路:将每个点拆分为两个点 a与a' ,a表示为1,a'表示为0。那么条件给的每个边自然就会存在矛盾,然后根据2-SAT建边就行了。
#include<iostream> #include<cstring> #include<cstdio> #include<algorithm> #include<cmath> #include<vector> #define Maxn 3010 #define Maxm 1000000 using namespace std; int dfn[Maxn],low[Maxn],vi[Maxn],head[Maxn],e,n,m,lab,top,Stack[Maxn],num,id[Maxn]; struct Edge{ int u,v,next,l; }edge[Maxm]; void init() { int i,j; memset(dfn,0,sizeof(dfn)); memset(low,0,sizeof(low)); memset(head,-1,sizeof(head)); memset(id,0,sizeof(id)); memset(vi,0,sizeof(vi)); e=lab=num=top=0; } void add(int u,int v) { edge[e].u=u,edge[e].v=v,edge[e].next=head[u],head[u]=e++; } void Tarjan(int u) { int i,j,v; dfn[u]=low[u]=++lab; Stack[top++]=u; vi[u]=1; for(i=head[u];i!=-1;i=edge[i].next) { v=edge[i].v; if(!dfn[v]) { Tarjan(v); low[u]=min(low[u],low[v]); } if(vi[v]) low[u]=min(low[u],dfn[v]); } if(low[u]==dfn[u]) { ++num; do{ i=Stack[--top]; vi[i]=0; id[i]=num; }while(i!=u); } } int solve() { int i,j; for(i=1;i<=n*2;i++) { if(!dfn[i]) Tarjan(i); } for(i=1;i<=n;i++) { if(id[i]==id[i+n]) return 0; } return 1; } int main() { int i,j,a,b,c; char str[10]; while(scanf("%d%d",&n,&m)!=EOF) { init(); for(i=1;i<=m;i++) { scanf("%d%d%d%s",&a,&b,&c,&str); a++,b++; if(str[0]=='O') { if(c==0) { add(a,b+n); add(a,b); add(b,a+n); add(b,a); add(a+n,b+n); add(b+n,a+n); } else { add(a+n,b); add(b+n,a); } } if(str[0]=='A') { if(c==0) { add(a,b+n); add(b,a+n); } else { add(a+n,b); add(a,b); add(b+n,a); add(b,a); add(a+n,b+n); add(b+n,a+n); } } if(str[0]=='X') { if(c==0) { add(a,b); add(b+n,a+n); add(b,a); add(a+n,b+n); } else { add(a,b+n); add(b,a+n); add(a+n,b); add(b+n,a); } } } if(solve()) printf("YES\n"); else printf("NO\n"); } return 0; }