感觉:这题看了一晚上了,看了所有的解题报告才明天怎么回事……昨天自学没理解好2SAT啊,所以连边不知道怎么连,而且看了别人的解题报告了也看不明白为什么要那样连,晕……
思路:因为给出结点 a ,b,值 c,还有判断方式OP,这种一看当然就知道是用2SAT做了。为什么说是深刻理解2SAT呢,因为……2SAT中说过,只有关系确定的才能连边,否则不能连边;还有一个重要的是,如果某个条件必须为某个值时,自身与自身的相反条件也要连边,具体看下面解释:
现在设 2*a为1,2*a+1为0;当然 2*b为1,2*b+1为0:
1.当OP为’And‘时:
(1)当c=1时,那么只有a 与 b同时为1时,a AND b才等于1,并且有且只有当a与b都为1时这个条件才成立,所以a与b一定要等1,所以连边<2*a+1,2*a>,<2*b+1,2*b>,表示不管怎么样,a与b的情况都等于1,即:当a等于0时a必等于1,b等于0时b必等于1,这个刚开始我看别人的解题报告就是这么说的,然后自己也没太理解,其实真正的内涵就是强制执行a与b都等于1 !(如果a等于1了的话当然这条边就没用了,如果a等于0的话,那么这条连就可以起到把a强制等于1以符合题目条件情况了,就是如此简单,得慢慢理解)
(2)当c=0时,那么当a等于0时,b可能为0也可以为1,所以是不确定关系,由上面说的一定是确定关系才能连边,所以a为0的情况就不能连边了;当a等于1时,b一定为0才能使 a AND b =0,所以连边:<2*a,2*b+1>,当然还有<2*b,2*a,+1>。
2.当OP为OR时,
(1)当c=1时,那么当a=1时,b=1或者b=0,所以当a=1时出现了两种关系,就是不确定了,就不用连边了;当a=0时,那么b一定=1,所以是确定关系,连边:<2*a+1,2*b>,当然还有<2*b+1,2*a>。
(2)当c=0时,那么只有当a=b=0这个关系,所以这个和上面1(1)情况就一样了,上面是强制执行a=b=1的情况,而这里因为只有a=b=0的情况,所以也要强制执行a=b=0,即连边:<2*a,2*a+1>,<2*b,2*b+1>。
3.当OP为XOR时,因为如果a=1,那么b必=0;a=0,b必=1;b=1,a必=0;b=0,a必=1。如此看,这四个关系都是确定的,所以都要连边,但是其实我们可以不连,一条边都不用连,因为出a=1的时候一定不会再出现a=0了,这四条边是不会产生矛盾的,所以强连通缩点后不会出现belong[2*a]=belong[2*a+1]的情况的,所以连了也没用,只是多加了点判断的时间罢了……这在别人的解题报告里说的是形成了组环了,都是一个意思。比如:a=1,b=0与b=0,a=1在tarjan中会形成一个新的结点,也就是自环,所以……在异或这种情况中只能选择a=0或者a=1,所以不会出现矛盾……故不用连边了!
#include <iostream> #include <cstdio> #include <fstream> #include <algorithm> #include <cmath> #include <deque> #include <vector> #include <list> #include <queue> #include <string> #include <cstring> #include <map> #include <stack> #include <set> #define PI acos(-1.0) #define mem(a,b) memset(a,b,sizeof(a)) #define sca(a) scanf("%d",&a) #define sc(a,b) scanf("%d%d",&a,&b) #define pri(a) printf("%d\n",a) #define lson i<<1,l,mid #define rson i<<1|1,mid+1,r #define MM 200005 #define MN 2010 #define INF 1000000007 #define eps 1e-7 using namespace std; typedef long long ll; int DFN[MN],vis[MN],LOW[MN],Stack[MN*10],belong[MN],tem,Count,top; vector<int>e[MN]; void tarjan(int u) { DFN[u]=LOW[u]=++tem; vis[u]=true; Stack[++top]=u; int v,i,l=e[u].size(); for(i=0;i<l;i++) { v=e[u][i]; if(!DFN[v]) { tarjan(v); LOW[u]=min(LOW[u],LOW[v]); } else if(vis[v]&&DFN[v]<LOW[u]) LOW[u]=DFN[v]; } if(DFN[u]==LOW[u]) { Count++; do { v=Stack[top--]; vis[v]=false; belong[v]=Count; }while(v!=u); } } bool twoSAT(int n) { for(int i=0;i<2*n;i++) if(!DFN[i]) tarjan(i); for(int i=0;i<n;i++) if(belong[2*i]==belong[2*i+1]) return false; return true; } int main() { int n,m,i,a,b,c; char s[5]; sc(n,m); for(i=0;i<m;i++) { scanf("%d%d%d%s",&a,&b,&c,s); if(s[0]=='A') { if(c) { e[2*a+1].push_back(2*a); e[2*b+1].push_back(2*b); } else { e[2*a].push_back(2*b+1); e[2*b].push_back(2*a+1); } } else if(s[0]=='O') { if(c) { e[2*a+1].push_back(2*b); e[2*b+1].push_back(2*a); } else { e[2*a].push_back(2*a+1); e[2*b].push_back(2*b+1); } } } if(twoSAT(n)) puts("YES"); else puts("NO"); return 0; }