参看《由对称性解2-SAT问题》学习....2-sat用于解决一类问题..每组两个元素或者说一类物品有两种状态..每组(类)选且仅选一个..某些元素(状态)不能共存..通常是问能否选择成功..若成功输出选择方案...
本题很裸...而且只是要求能否成功...判断一个2-sat是否成功..就是连了边用Tarjan求强联通分量...若同组的两个在一个强联通分量中...则说明不可成功....因为一个强联通分量的意思是这个内部的点选择了其中一个..内部其他的点就必须全部选择..所以与题目要求矛盾...
Program:
#include<iostream>
#include<stdio.h>
#include<string.h>
#include<cmath>
#include<queue>
#include<stack>
#include<set>
#include<algorithm>
#define ll long long
#define oo 10007
#define pi acos(-1.0)
#define MAXN 2005
using namespace std;
vector<int> T[MAXN];
int n,dfn[MAXN],low[MAXN],_DfsIndex,tpnum,tp[MAXN];
stack<int> mystack;
bool instack[MAXN];
void tarjan(int x)
{
int i,y,m=T[x].size();
dfn[x]=low[x]=++_DfsIndex;
mystack.push(x);
instack[x]=true;
for (i=0;i<m;i++)
{
y=T[x][i];
if (!dfn[y])
{
tarjan(y);
low[x]=min(low[x],low[y]);
}else
if (instack[y])
low[x]=min(low[x],dfn[y]);
}
if (low[x]==dfn[x])
{
tpnum++;
do
{
x=mystack.top();
mystack.pop();
instack[x]=false;
tp[x]=tpnum;
}while(low[x]!=dfn[x]);
}
return;
}
bool judge()
{
int i;
for (i=1;i<=n;i++)
if (tp[i*2-1]==tp[i*2]) return false;
return true;
}
int main()
{
int i,m;
while (~scanf("%d",&n))
{
for (i=1;i<=n*2;i++) T[i].clear();
scanf("%d",&m);
while (m--)
{
int p0,x0,p1,x1;
scanf("%d%d%d%d",&x0,&x1,&p0,&p1);
x0++,x1++;
T[x1*2-p1].push_back(x0*2-(1^p0));
T[x0*2-p0].push_back(x1*2-(1^p1));
}
memset(dfn,0,sizeof(dfn));
memset(instack,false,sizeof(instack));
_DfsIndex=tpnum=0;
while (!mystack.empty()) mystack.pop();
for (i=1;i<=n*2;i++)
if (!dfn[i]) tarjan(i);
if (judge()) printf("YES\n");
else printf("NO\n");
}
return 0;
}