• POJ 3678 2SAT基础题


    题目链接: http://poj.org/problem?id=3678

    题目大意:

      有一个大小为N的集合={x1,x2..xn},xi=0或1,现在给出它们之间的一些逻辑运算的结果(比如x1 and x2=1),逻辑运算有AND OR XOR三种,问是否存在一种满足所有条件的取值方案。

    分析:

      (这题开始我构图出错了,叫lin神看了下,他提出一个观点,如果类似 u,v,1  AND这样的数据,说明u,v的1必须都选,那么就把u的0连向u的1,v的0连向v的1,这样的目的是使得推出矛盾)

      由于集合中的每个元素只有两种选择,要么为0,要么为1,所以可以将这个问题转化成一个2-sat判定问题。对于集合中的每个元素,看做两个点:i和i+n。i表示这个元素取0,i+n表示这个元素取1。那么,剩下的问题就是如何构图了。

      首先,理解清楚求解2-sat的方法是很必要的。求解2-sat的方法是,构造出一个图,图中的有向边<x,y>表示选x时必须选y。只有这个图满足这个条件,并且所有的边都是对称的(假如原问题能转化成2-sat判定,那么图中的边必然是对称的),那么就可以利用求强连通分量缩点的方法来验证2-sat问题。

    对于本题,我们逐个考虑每个逻辑运算:

    1、A AND B=0.这要求A和B不同时为1。既然不同时为1,那么A取1时,B必须取0;B取1时,A必须取0.所以,要连得边便是A+n->B, B+n->A。

    2、A AND B=1.这要求A和B同时为1。换句话说,A和B不能是0.那要怎么样体现在图中呢?我们知道,判断一个2-sat问题是否存在合法方案的方法是,缩点后判断有没有两个同组点属于同一个连通分量。我们需要A和B都必须是1,那么我们就让A和B必须选0时无解即可。也就是说,连边A->A+n, B->B+n。这样的话,假如构图完成后,A必须取0,那么由于存在边A->A+n,所以A也必须取1,那么就不可能是一个合法方案。所以,这两条边能保证,有合法方案的话,一定是A取1(选A+n节点)的情况。

    3、A OR B=0.这要求A和B同时为0.方法和2类似,方向变一下而已,理由同上。

    4、A XOR B=0.这要求A=B。所以,A为0时,B必须为0,同理B为0时,A必须为0.所以添加边:A->B,B->A,A+n->B+n,B+n->A+n。

    以上的分析过程是摘自上面的链接博客,自己必须深刻体会,并在今后中会应用,尤其是第2点和第3点,而其他的就是要注意有什么限制就连什么边,不能多连,也不能少连。。

    代码:

    poj3678
      1 /*3678    Accepted    488K    141MS    C++    3238B    2012-04-25 13:26:00*/
      2 #include <cstdio>
      3 #include <cstring>
      4 #include <cmath>
      5 #include <iostream>
      6 #include <algorithm>
      7 #include <vector>
      8 using namespace std;
      9 
     10 #define mpair make_pair
     11 #define pii pair<int,int>
     12 #define MM(a,b) memset(a,b,sizeof(a));
     13 typedef long long lld;
     14 typedef unsigned long long u64;
     15 template<class T> bool up_max(T& a,const T& b){return b>a? a=b,1 : 0;}
     16 template<class T> bool up_min(T& a,const T& b){return b<a? a=b,1 : 0;}
     17 #define maxn 2020
     18 
     19 int n,m;
     20 vector<int> adj[maxn];
     21 
     22 int Bcnt, Index, Top;
     23 int low[maxn], dfn[maxn];
     24 bool instack[maxn];
     25 int belong[maxn],stack[maxn];
     26 void Tarjan(int u){
     27     low[u]= dfn[u]= ++Index;
     28     stack[++Top]= u;
     29     instack[u]= 1;
     30     for(int i=0;i<adj[u].size();++i){
     31         int v= adj[u][i];
     32         if( !dfn[v] ){
     33             Tarjan( v );
     34             up_min( low[u], low[v] );
     35         }
     36         else if( instack[v] )
     37             up_min( low[u], dfn[v] );
     38     }
     39     if( low[u] == dfn[u] ){
     40         ++Bcnt;
     41         int v;
     42         do{
     43             v= stack[Top--];
     44             instack[v]= 0;
     45             belong[v]= Bcnt;
     46         }while( u!=v );
     47     }
     48 }
     49 
     50 int main()
     51 {
     52     while( cin>>n>>m ){
     53         for(int i=1;i<=n+n;++i) adj[i].clear();
     54         for(int i=1;i<=m;++i){
     55             int u,v,w; char ch[10];
     56             scanf("%d%d%d%s", &u, &v, &w, ch);
     57             ++u, ++v;
     58             /// u+u-1: 0;  u+u: 1;
     59             if( *ch == 'A' ){
     60                 if( 1==w ){
     61                     adj[u+u].push_back( v+v );
     62                     adj[v+v].push_back( u+u );
     63                     adj[u+u-1].push_back( u+u );
     64                     adj[v+v-1].push_back( v+v );
     65                 }
     66                 else{
     67                     adj[u+u].push_back( v+v-1 );
     68                     adj[v+v].push_back( u+u-1 );
     69                 }
     70             }
     71             else if( *ch == 'O' ){
     72                 if( 1==w ){
     73                     adj[u+u-1].push_back( v+v );
     74                     adj[v+v-1].push_back( u+u );
     75                 }
     76                 else{
     77                     adj[u+u-1].push_back( v+v-1 );
     78                     adj[v+v-1].push_back( u+u-1 );
     79                     adj[u+u].push_back( u+u-1 );
     80                     adj[v+v].push_back( v+v-1 );
     81                 }
     82             }
     83             else if( *ch == 'X' ){
     84                 if( 1==w ){
     85                     adj[u+u].push_back( v+v-1 );
     86                     adj[v+v].push_back( u+u-1 );
     87                     adj[u+u-1].push_back( v+v );
     88                     adj[v+v-1].push_back( u+u );
     89                 }
     90                 else{
     91                     adj[u+u].push_back( v+v );
     92                     adj[v+v].push_back( u+u );
     93                     adj[u+u-1].push_back( v+v-1 );
     94                     adj[v+v-1].push_back( u+u-1 );
     95                 }
     96             }
     97         }
     98 
     99         Bcnt= Index= Top= 0;
    100         for(int i=1;i<=n+n;++i) low[i]= dfn[i]= instack[i]= 0;
    101         for(int i=1;i<=n+n;++i)
    102             if( !dfn[i] )
    103                 Tarjan( i );
    104         for(int i=1;i<=n;++i){
    105             if( belong[i+i-1] == belong[i+i] ){
    106                 puts("NO"); break;
    107             }
    108             if( i==n ) puts("YES");
    109         }
    110     }
    111 }

     

    一毛原创作品,转载请注明出处。
  • 相关阅读:
    牛客noip前集训营(第一场)提高T1
    约数的个数
    牛客OI赛制测试赛2 D 星光晚餐
    牛客OI赛制测试赛2 C 数组下标
    牛客OI赛制测试赛2 A 无序组数
    [题解] codevs 1486 愚蠢的矿工
    字典(trie)树--从入门到入土
    [题解] cogs 2240 架设电话线路
    [题解] cogs 1669 神秘的咒语
    LCIS 最长上升公共子序列问题
  • 原文地址:https://www.cnblogs.com/yimao/p/2469864.html
Copyright © 2020-2023  润新知