参看《由对称性解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; }