题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=3062
2 1 0 1 1 1
YES
2-SAT入门题
对于(a,a'),(b,b'),如果a,b构成仇恨关系,那么如果选a,则必须选b',选b则必须选a',建边a->b',b->a'表示必须关系,也就是说如果选了连通分量里的一个点,那么其余所有边都必须选,则本体a,a'在一个连通分量里为非法,只需要判断就好啦。。。
//#include <bits/stdc++.h> #include <iostream> #include <cstdio> #include <cstring> #include <cmath> #include <algorithm> using namespace std; const int MAXN = 1e6+7; struct node { int v,next; }edge[MAXN]; int head[MAXN],index; void add_edge(int u,int v) { edge[index].v=v; edge[index].next=head[u]; head[u]=index++; } int DFN[MAXN],low[MAXN],stack_[MAXN],in_stack[MAXN],belong[MAXN]; int cir,top,temp; void Tarjan(int u) { int p; DFN[u]=low[u]=++temp; in_stack[u]=1; stack_[top++]=u; for(int i=head[u]; i+1; i=edge[i].next) { int v=edge[i].v; if(!DFN[v]) { Tarjan(v); low[u]=min(low[u],low[v]); } else if(in_stack[v]) { low[u]=min(low[u],DFN[v]); } } if(low[u]==DFN[u]) { ++cir; do{ p=stack_[--top]; in_stack[p]=0; belong[p]=cir; }while(p!=u); } } int main() { int n,m; while(scanf("%d",&n)!=EOF) { int a,b,c,d; temp=cir=top=index=0; memset(DFN,0,sizeof(DFN)); memset(head,-1,sizeof(head)); memset(in_stack,0,sizeof(in_stack)); scanf("%d",&m); for(int i=0; i<m; ++i) { scanf("%d%d%d%d",&a,&b,&c,&d); a=(a<<1)+c; b=(b<<1)+d; add_edge(a,b^1); add_edge(b,a^1); } for(int i=0; i<n<<1; ++i) if(!DFN[i]) Tarjan(i); int flag=0; for(int i=0; i<n; ++i) { if(belong[i<<1]==belong[(i<<1)^1]) flag=1; } if(flag)printf("NO\n"); else printf("YES\n"); } return 0; }