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;
}