[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/

posted @ 2018-08-21 11:24  real_l  阅读(317)  评论(0编辑  收藏  举报