题意:给出n个数和m组数对应的位运算,断定n个数是否满足m组位运算
很久以前就听说2-SAT了,只是最近才花时间看了一下,觉得这个东西真是神奇。
对于2-SAT只能把1个点拆成2个点,对于K-SAT问题,貌似是NP问题。。我也不太清楚,反正如果你拆成2个以上的点,那就不要用2-SAT解了。
前言:我只是谈一下我的体会,没有证明一定正确,但也许能启发你的思路。
2-SAT主要就是处理“矛盾”与“必然”的一种方法,其算法是应用了强连通
a1表示a取1,a0表示a取0,b0,b1同理
对于矛盾:
举例说明 如果a AND b=1,如果我们取a0,这样肯定是无解的,那我们就连一条a0-->a1的边,表示取a0就必须要取a1,这样就就出现了矛盾,b同理
http://blog.sina.com.cn/s/blog_68629c7701010gf1.html 这篇文章举例论述了矛盾的问题,值得一看。
对于必然:
同样举例说明 如果a OR b=1,如果我们取a0,则我们必须(注意这里我用的是“必须”)要取b1,那我们就连一条a0-->b1的边
再举一个例子可以让我们思路更清晰:
如果a OR b=1,如果我们取a1的话,应该怎么连呢??思考一下再往后看。
如果取a1,那么b可以取b1或者b0,失去了必然性(知道为什么刚才我要强调“必须”了吧),就不能连边
总结起来就是,连接的有向边表示的是有序的必然关系
这里又强调了“有序”,因为如果a OR b=1,我们取a0就必须要取b1(上面解释过原因了),我们需要连一条有向边,然而反过来,如果我们取b1,我们不一定要取a0,取a1也可以就不用连边
表达能力不好,对2-SAT的领悟有限,且以上写的不保证正确性(至少我做对题了),也不会证明。。只是启发作用,加速理解,就像“谐音背单词”一样,应该还是有一些作用的
如果有那个地方写错了,谢谢指正
1 #include <cstdio> 2 #include <cstdlib> 3 #include <cstring> 4 #include <iostream> 5 #define N 40000 6 #define M 5000000 7 using namespace std; 8 int n,m,cnt,t,divg,belong[N],head[M],next[M],to[M],dfn[N],low[N],p,stack[M]; 9 bool fg[N];char str[9]; 10 inline void add(int u,int v) 11 { 12 to[cnt]=v; next[cnt]=head[u]; head[u]=cnt++; 13 } 14 void read() 15 { 16 memset(head,-1,sizeof head); cnt=0; 17 memset(fg,0,sizeof fg); 18 memset(dfn,0,sizeof dfn); 19 memset(belong,0,sizeof belong); 20 t=0; divg=0; p=0; 21 for(int i=1,a,b,c;i<=m;i++) 22 { 23 scanf("%d %d %d %s",&a,&b,&c,str+1); 24 a++; b++; 25 if(str[1]=='A') 26 { 27 if(c==1) add(a+n,a),add(b+n,b),add(a,b),add(b,a); 28 else add(a,b+n),add(b,a+n); 29 } 30 else if(str[1]=='O') 31 { 32 if(c==1) add(a+n,b),add(b+n,a); 33 else add(a,a+n),add(b,b+n); 34 } 35 else 36 { 37 if(c==1) add(a,b+n),add(b,a+n),add(a+n,b),add(b+n,a); 38 else add(a+n,b+n),add(b+n,a+n),add(a,b),add(b,a); 39 } 40 } 41 } 42 void dfs(int u) 43 { 44 t++; 45 dfn[u]=low[u]=t; 46 stack[++p]=u; fg[u]=true; 47 for(int i=head[u];~i;i=next[i]) 48 { 49 if(!dfn[to[i]]) 50 { 51 dfs(to[i]); 52 low[u]=min(low[u],low[to[i]]); 53 } 54 else if(fg[to[i]]) low[u]=min(low[u],dfn[to[i]]); 55 } 56 if(dfn[u]==low[u]) 57 { 58 divg++; 59 int tmp=-1; 60 while(tmp!=u) 61 { 62 tmp=stack[p--]; 63 belong[tmp]=divg; 64 fg[tmp]=false; 65 } 66 } 67 } 68 bool go() 69 { 70 for(int i=1;i<=2*n;i++) 71 if(!dfn[i]) dfs(i); 72 for(int i=1;i<=n;i++) 73 if(belong[i]==belong[i+n]) return false; 74 return true; 75 } 76 int main() 77 { 78 while(scanf("%d%d",&n,&m)!=EOF) 79 { 80 read(); 81 if(go()) printf("YES\n"); 82 else printf("NO\n"); 83 } 84 return 0; 85 }
假期最后一份解题报告了,明天要报道,后天,大后天考试,又要挂科了。。