zoukankan      html  css  js  c++  java
  • POJ 3678(2SAT)

    题意:给出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 }

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

    没有人能阻止我前进的步伐,除了我自己!
  • 相关阅读:
    Android中开发习惯
    Activity、Window和View三者间的关系有一定的见解
    Android底层有一定的认识,研究过相关的Android源码
    安卓工程的启动过程
    OAuth2认证有一定的了解
    屏幕适配经验
    NOIP模拟赛14
    NOIP模拟赛13
    NOIP模拟赛12
    NOIP模拟赛11
  • 原文地址:https://www.cnblogs.com/proverbs/p/2664208.html
Copyright © 2011-2022 走看看