POJ 3678(2-SAT)

题意:给出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的领悟有限,且以上写的不保证正确性(至少我做对题了),也不会证明。。只是启发作用,加速理解,就像“谐音背单词”一样,应该还是有一些作用的

如果有那个地方写错了,谢谢指正

 

View Code
 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 }

 

 假期最后一份解题报告了,明天要报道,后天,大后天考试,又要挂科了。。

posted @ 2012-08-30 18:04  proverbs  阅读(251)  评论(0编辑  收藏  举报