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 }

 

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

你可能感兴趣的:(poj)