zoukankan      html  css  js  c++  java
  • poj 3678 Katu Puzzle(2-sat)

    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

    X0 = 1, X1 = 1, X2 = 0, X3 = 1.

    Source

     
    胡乱地搞,竟然就AC了
    借用别人的解题报告

    思路:因为给出结点 a ,b,值 c,还有判断方式OP,这种一看当然就知道是用2SAT做了。为什么说是深刻理解2SAT呢,因为……2SAT中说过,只有关系确定的才能连边,否则不能连边;还有一个重要的是,如果某个条件必须为某个值时,自身与自身的相反条件也要连边,具体看下面解释:

    现在设 2*a为1,2*a+1为0;当然 2*b为1,2*b+1为0:

    1.当OP为’And‘时:

    (1)当c=1时,那么只有a 与 b同时为1时,a  AND b才等于1,并且有且只有当a与b都为1时这个条件才成立,所以a与b一定要等1,所以连边<2*a+1,2*a>,<2*b+1,2*b>,表示不管怎么样,a与b的情况都等于1,即:当a等于0时a必等于1,b等于0时b必等于1,这个刚开始我看别人的解题报告就是这么说的,然后自己也没太理解,其实真正的内涵就是强制执行a与b都等于1 !(如果a等于1了的话当然这条边就没用了,如果a等于0的话,那么这条连就可以起到把a强制等于1以符合题目条件情况了,就是如此简单,得慢慢理解)

    (2)当c=0时,那么当a等于0时,b可能为0也可以为1,所以是不确定关系,由上面说的一定是确定关系才能连边,所以a为0的情况就不能连边了;当a等于1时,b一定为0才能使 a AND b =0,所以连边:<2*a,2*b+1>,当然还有<2*b,2*a,+1>。

    2.当OP为OR时,

    (1)当c=1时,那么当a=1时,b=1或者b=0,所以当a=1时出现了两种关系,就是不确定了,就不用连边了;当a=0时,那么b一定=1,所以是确定关系,连边:<2*a+1,2*b>,当然还有<2*b+1,2*a>。

    (2)当c=0时,那么只有当a=b=0这个关系,所以这个和上面1(1)情况就一样了,上面是强制执行a=b=1的情况,而这里因为只有a=b=0的情况,所以也要强制执行a=b=0,即连边:<2*a,2*a+1>,<2*b,2*b+1>。

    3.当OP为XOR时,因为如果a=1,那么b必=0;a=0,b必=1;b=1,a必=0;b=0,a必=1。如此看,这四个关系都是确定的,所以都要连边,但是其实我们可以不连,一条边都不用连,因为出a=1的时候一定不会再出现a=0了,这四条边是不会产生矛盾的,所以强连通缩点后不会出现belong[2*a]=belong[2*a+1]的情况的,所以连了也没用,只是多加了点判断的时间罢了……这在别人的解题报告里说的是形成了组环了,都是一个意思。比如:a=1,b=0与b=0,a=1在tarjan中会形成一个新的结点,也就是自环,所以……在异或这种情况中只能选择a=0或者a=1,所以不会出现矛盾……故不用连边了!

      1 #pragma comment(linker, "/STACK:1024000000,1024000000")
      2 #include<iostream>
      3 #include<cstdio>
      4 #include<cstring>
      5 #include<cmath>
      6 #include<math.h>
      7 #include<algorithm>
      8 #include<queue>
      9 #include<set>
     10 #include<bitset>
     11 #include<map>
     12 #include<vector>
     13 #include<stdlib.h>
     14 #include <stack>
     15 using namespace std;
     16 #define PI acos(-1.0)
     17 #define max(a,b) (a) > (b) ? (a) : (b)  
     18 #define min(a,b) (a) < (b) ? (a) : (b)
     19 #define ll long long
     20 #define eps 1e-10
     21 #define MOD 1000000007
     22 #define N 1006
     23 #define inf 1e12
     24 int n,m;
     25 vector<int> e[N];
     26 
     27 int tot;
     28 int head[N];
     29 int vis[N];
     30 int tt;
     31 int scc;
     32 stack<int>s;
     33 int dfn[N],low[N];
     34 int col[N];
     35 struct Node
     36 {
     37     int from;
     38     int to;
     39     int next;
     40 }edge[N*N];
     41 void init()
     42 {
     43     tot=0;
     44     scc=0;
     45     tt=0;
     46     memset(head,-1,sizeof(head));
     47     memset(dfn,-1,sizeof(dfn));
     48     memset(low,0,sizeof(low));
     49     memset(vis,0,sizeof(vis));
     50     memset(col,0,sizeof(col));
     51 }
     52 void add(int s,int u)//邻接矩阵函数
     53 {
     54     edge[tot].from=s;
     55     edge[tot].to=u;
     56     edge[tot].next=head[s];
     57     head[s]=tot++;
     58 }
     59 void tarjan(int u)//tarjan算法找出图中的所有强连通分支
     60 {
     61     dfn[u] = low[u]= ++tt;
     62     vis[u]=1;
     63     s.push(u);
     64     int cnt=0;
     65     for(int i=head[u];i!=-1;i=edge[i].next)
     66     {
     67         int v=edge[i].to;
     68         if(dfn[v]==-1)
     69         {
     70         //    sum++;
     71             tarjan(v);
     72             low[u]=min(low[u],low[v]);
     73         }
     74         else if(vis[v]==1)
     75           low[u]=min(low[u],dfn[v]);
     76     }
     77     if(dfn[u]==low[u])
     78     {
     79         int x;
     80         scc++;
     81         do{
     82             x=s.top();
     83             s.pop();
     84             col[x]=scc;
     85             vis[x]=0;
     86         }while(x!=u);
     87     }
     88 }
     89 bool two_sat(){
     90     
     91     for(int i=0;i<2*n;i++){
     92         if(dfn[i]==-1){
     93             tarjan(i);
     94         }
     95     }
     96     for(int i=0;i<n;i++){
     97         if(col[2*i]==col[2*i+1]){
     98             return false;
     99         }
    100     }
    101     return true;
    102 }
    103 int main()
    104 {
    105     while(scanf("%d%d",&n,&m)==2){
    106          init();
    107          for(int i=0;i<N;i++) e[i].clear();
    108          while(!s.empty()){
    109              s.pop();
    110          }
    111         int a,b,c;
    112         char s[6];
    113         for(int i=0;i<m;i++){
    114             scanf("%d%d%d%s",&a,&b,&c,s);
    115             if(s[0]=='A'){
    116                 if(c==1){
    117                     //e[2*a+1].push_back(2*a);
    118                     //e[2*b+1].push_back(2*b);
    119                     add(2*a+1,2*a);
    120                     add(2*b+1,2*b);
    121                 }
    122                 else{
    123                     //e[2*a].push_back(2*b+1);
    124                     //e[2*b].push_back(2*a+1);
    125                     add(2*a,2*b+1);
    126                     add(2*b,2*a+1);
    127                 }
    128             }
    129             else if(s[0]=='O'){
    130                 if(c==1){
    131                     //e[2*a+1].push_back(2*b);
    132                     //e[2*b+1].push_back(2*a);
    133                     add(2*a+1,2*b);
    134                     add(2*b+1,2*a);
    135                 }
    136                 else{
    137                     //e[2*a].push_back(2*a+1);
    138                     //e[2*b].push_back(2*b+1);
    139                     add(2*a,2*a+1);
    140                     add(2*b,2*b+1);
    141                 }
    142             }
    143         }
    144         if(two_sat()){
    145             printf("YES
    ");
    146         }
    147         else{
    148             printf("NO
    ");
    149         }
    150     }
    151     return 0;
    152 }
    View Code
  • 相关阅读:
    Linux中的官方源、镜像源汇总
    提示"libc.so.6: version `GLIBC_2.14' not found"
    win8.1 安装msi软件出现 2503、2502
    平均负载(Load average)
    oracle 导入报错:field in data file exceeds maximum length
    一个命令的输出作为另外一个命令的输入
    Http 状态码
    Linux 命令总结
    ORA-12505: TNS: 监听程序当前无法识别连接描述符中所给出的SID等错误解决方法
    轻松应对IDC机房带宽突然暴涨问题
  • 原文地址:https://www.cnblogs.com/UniqueColor/p/4814122.html
Copyright © 2011-2022 走看看