zoukankan      html  css  js  c++  java
  • [POJ3678] Katu Puzzle

    Katu Puzzle

    Time Limit: 1000MS

    Memory Limit: 65536K

    Total Submissions: 11770

    Accepted: 4345

    Description

    Katu Puzzle is presented as a directed graph G(V, E) with each edge e(a, b) labeled by a boolean operator op (one of AND, OR, XOR) and an integer c (0 ≤ c ≤ 1). One Katu is solvable if one can find each vertex Vi a value Xi (0 ≤ Xi ≤ 1) such that for each edge e(a, b) labeled by op and c, the following formula holds:

    Xa op Xb = c

    The calculating rules are:

    AND

    0

    1

    0

    0

    0

    1

    0

    1

    OR

    0

    1

    0

    0

    1

    1

    1

    1

    XOR

    0

    1

    0

    0

    1

    1

    1

    0

    Given a Katu Puzzle, your task is to determine whether it is solvable.

    Input

    The first line contains two integers N (1 ≤ N ≤ 1000) and M,(0 ≤ M ≤ 1,000,000) indicating the number of vertices and edges.
    The following M lines contain three integers a (0 ≤ a < N), b(0 ≤ b < N), c and an operator op each, describing the edges.

    Output

    Output a line containing "YES" or "NO".

    Sample Input

    4 4
    0 1 1 AND
    1 2 1 OR
    3 2 0 AND
    3 0 0 XOR

    Sample Output

    YES

    Hint

    _X_0 = 1, _X_1 = 1, _X_2 = 0, _X_3 = 1.

    Source

    POJ Founder Monthly Contest – 2008.07.27, Dagger

    题解

    POJ3678

    上面本来是有一个表格的,可能是复制下来的时候炸格式了,没事,博主再复述一遍题意

    有N个变量(x_0-x_{n-1}),每个变量的可能取值是0或1.给定M个算式,每个算式形如(x_a) (op) (x_b) (=) (c),其中a,b是两个变量的编号,c是数字0或1,op是ans,or,xor三个位运算之一.求是否存在对每个变量的合法取值,是所有算式都成立

    数据范围:(1<=N<=1000,1<=M<=10^6) 我们发现,如果只有xor运算,很显然我们是可以用扩展域并查集做的,但是现在有三种运算,又发现每种运算仅涉及两个变量,那么考虑2-SAT

    在这里再简略的重复一下2-SAT的含义

    现有一个由N个布尔值组成的序列A,给出一些限制关系,比如A[x] AND A[y]=0、A[x] OR A[y] OR A[z]=1等,要确定A[0..N-1]的值,使得其满足所有限制关系。这个称为SAT问题,特别的,若每种限制关系中最多只对两个元素进行限制,则称为2-SAT问题。

    2-SAT就是把变量之间的关系转化为图形去解决

    我们设对于一个变量i为表示这个变量的值为0的域,i+n为表示这个变量为1的域

    (u,v)表示u,v之间有一条有向边,表示根据u必然能推出v

    and

    a and b=1

    要求a和b都为1,那么如果题目a为0,则必须要让a=1,a->a+n

    同理,如果b为0,b->b+n

    a and b=0

    要求a和b至少要有一个为0,那么如果a=1,则b必然为0,a+n->b
    同理,b=1,b+n->a

    or

    a or b=1

    要求a和b至少有一个为1,如果a=0,则必然b=1,a->b+n
    同理,b=0,b->a+n

    a or b=0

    要求a和b都要为0,如果其中有一个为1,把它连到自己为0的域
    a+n->a,b+n->b

    xor

    a xor b=1

    要求a和b不同,即a=1,b=0,a=0,b=1
    同时,b=1,a=0,b=0,a=1
    a+n->b,a->b+n
    b+n->a,b->a+n

    a xor b=0

    要求a和b相同,类比上面
    a->b,b->a
    a+n->b+n,b+n->a+n

    建完图后跑tarjan缩点就可以了

    判断:判断一个点为0的域和为1的域是否在同一个scc里面,如果在,就表示不合法,否则合法

    Code

    #include<iostream>
    #include<cstdio>
    #include<stack>
    #include<cstring>
    #include<string>
    #include<cstdlib>
    #define Max(a,b) (a)>(b)?(a):(b)
    #define Min(a,b) (a)<(b)?(a):(b)
    
    using namespace std;
    
    const int N=2010;
    
    inline void in(int &ans)
    {
      ans=0;int f=1;char i=getchar();
      while(i<'0' || i>'9') {if(i=='-') f=-1;i=getchar();}
      while(i>='0' && i<='9') {ans=(ans<<1)+(ans<<3)+i-'0';i=getchar();}
      ans*=f;
    }
    
    stack<int>s;
    int n,m,cnt,dfscnt,scc;
    int nex[N*N],to[N*N],head[N*N];
    int sccno[N],dfn[N],low[N],num[N];
    
    void add(int a,int b)
    {
      to[++cnt]=b;
      nex[cnt]=head[a];
      head[a]=cnt;
    }
    
    void tarjan(int u)
    {
      dfn[u]=low[u]=++dfscnt; s.push(u);
      for(int i=head[u];i;i=nex[i])
        {
          if(!dfn[to[i]])
    	{
    	  tarjan(to[i]);
    	  low[u]=Min(low[u],low[to[i]]);
    	}
          else if(!sccno[to[i]]) low[u]=Min(low[u],dfn[to[i]]);
        }
      if(low[u]==dfn[u])
        {
          scc++;
          while(1)
    	{
    	  int x=s.top(); s.pop();
    	  num[scc]++;
    	  sccno[x]=scc;
    	  if(x==u) break;
    	}
        }
    }
    
    bool two_sat()
    {
      for(int i=0;i<=(n-1<<1);i++) if(!dfn[i]) tarjan(i);
      for(int i=0;i<n;i++)
        if(sccno[i]==sccno[i+n]) return 0;
      return 1;
    }
    
    int main()
    {
      in(n),in(m);
      
      for(int i=1;i<=m;i++)
        {
          int a,b,vl;char s[5];
          in(a),in(b),in(vl);scanf("%s",s);
          if(s[0]=='A')
    	{
    	  if(vl) add(a,a+n),add(b,b+n);
    	  else add(a+n,b),add(b+n,a);
    	}
          
          else if(s[0]=='O')
    	{
    	  if(vl) add(a,b+n),add(b,a+n);
    	  else add(a+n,a),add(b+n,b);
    	}
          
          else
    	{
    	  if(vl) add(a,b+n),add(b,a+n),add(a+n,b),add(b+n,a);
    	  else add(a,b),add(b,a),add(a+n,b+n),add(b+n,a+n);
    	}
        }
      if(two_sat()) puts("YES");
      else puts("NO");
      
      return 0;
    }
    

    博主蒟蒻,随意转载.但必须附上原文链接

    http://www.cnblogs.com/real-l/

  • 相关阅读:
    centos7 忘记mysql5.7密码
    阿里云Linux(Centos7)下搭建SVN服务器
    JAVA金额格式字符串转数值
    win10下RabbitMQ的安装和配置
    Oracle update 两表及以上关联更新,出现多值情况,不是一对一更新
    java.lang.OutOfMemoryError: java heap space
    bootstrap.min.css.map
    css 边距等常用设置
    html 标签
    数据库总结
  • 原文地址:https://www.cnblogs.com/real-l/p/9510335.html
Copyright © 2011-2022 走看看