zoukankan      html  css  js  c++  java
  • hdu 4421 Bit Magic

    【题意】

    这个函数是给A求B的,现在给你B,问你是否能有A的解存在。

     【2-SAT解法】

          对于每个A[i]的每一位运行2-sat算法,只要跑到强连通就可以结束,应为只要判断是否有解,后面拓扑求解就不需要了。构图和算法思想和基本的2-sat一致,详见我的2-sat博文。

      1 #include <stdio.h>
      2 #include <string.h>
      3 inline int min(int a,int b){return a>b?b:a;}
      4 struct edge
      5 {
      6     int v,next;
      7     edge(int d=0,int n=-1):v(d),next(n){}
      8     void set(int d,int n){v=d;next=n;}
      9 }data[500*2001];
     10 int head[1024],hn;
     11 void adde(int a,int b)
     12 {
     13     data[hn].set(b,head[a]);
     14     head[a]=hn++;
     15 }
     16 int n;
     17 int b[501][501];
     18 int dfn[1024],low[1024],sta[1024],belong[1024];
     19 bool ifin[1024];
     20 int top,group,dep;
     21 void tarjan(int u)
     22 {
     23     dfn[u]=low[u]=++dep;
     24     sta[++top]=u;
     25     ifin[u]=true;
     26     for (int i=head[u];i!=-1;i=data[i].next)
     27     {
     28         int v=data[i].v;
     29         if (!dfn[v])
     30         {
     31             tarjan(v);
     32             low[u]=min(low[u],low[v]);
     33         } else
     34         {
     35             if (ifin[v]) low[u]=min(low[u],dfn[v]);
     36         }
     37     }
     38     if (dfn[u]==low[u])
     39     {
     40         int j;
     41         ++group;
     42         do
     43         {
     44             j=sta[top--];
     45             belong[j]=group;
     46             ifin[j]=false;
     47         } while (u!=j);
     48     }
     49 }
     50 void init()
     51 {
     52     hn=dep=group=0;
     53     top=-1;
     54     memset(head,-1,sizeof head);
     55     memset(dfn,0,sizeof dfn);
     56     memset(ifin,false,sizeof ifin);
     57 }
     58 bool judge()
     59 {
     60     for (int i=0;i<n;++i)
     61         if (belong[i]==belong[i+n]) return false;
     62     return true;
     63 }
     64 bool solve()
     65 {
     66     for (int i=0;i<n;++i)
     67         for (int j=i;j<n;++j)
     68     {
     69         if (i==j && b[i][j]) return false;
     70         if (b[i][j]!=b[j][i]) return false;
     71     }
     72     for (int k=0;k<31;++k)
     73     {
     74         init();
     75         for (int i=0;i<n;++i)
     76             for (int j=i;j<n;++j)
     77         {
     78             int m=b[i][j]&(1<<k);
     79             if (i==j) continue;
     80             if (i&1 && j&1) // |
     81             {
     82                 if (m)
     83                 {
     84                     adde(i,j+n);
     85                     adde(j,i+n);
     86                 } else
     87                 {
     88                     adde(i+n,i);
     89                     adde(j+n,j);
     90                 }
     91             } else if (!(i&1) && !(j&1)) //&
     92             {
     93                 if (m)
     94                 {
     95                     adde(i,i+n);
     96                     adde(j,j+n);
     97                 } else
     98                 {
     99                     adde(i+n,j);
    100                     adde(j+n,i);
    101                 }
    102             } else   // ^
    103             {
    104                 if (m)
    105                 {
    106                     adde(i,j+n);
    107                     adde(j,i+n);
    108                     adde(j+n,i);
    109                     adde(i+n,j);
    110                 } else  //==
    111                 {
    112                     adde(i,j);
    113                     adde(j,i);
    114                     adde(i+n,j+n);
    115                     adde(j+n,i+n);
    116                 }
    117             }
    118         }
    119         for (int i=0;i<(n<<1);++i)
    120             if (!dfn[i]) tarjan(i);
    121         if (!judge()) return false;
    122     }
    123     return true;
    124 }
    125 int main()
    126 {
    127     while (~scanf("%d",&n))
    128     {
    129         for (int i=0;i<n;++i)
    130             for (int j=0;j<n;++j)
    131               scanf("%d",&b[i][j]);
    132         if (solve()) puts("YES"); else puts("NO");
    133     }
    134 }
    2-sat

    【并查集】

          主要思想是以A中每个元素的每一位作为一个基本单位,根据b中的值来确定每一位之间的等价关系,值相等的并在一个集合,每当能确定一个新的关系时验证原先的关系是否矛盾。不过在处理的时候有点小技巧,与2-sat的思想类似,扩充成2N个点,对于每一位,有个点代表其值,另一点代表其值的反。能确定一位的值时要同时更新这2点,从一方面说是充分发掘信息,另一方面说是为了异或运算的判断服务,因为异或不能确定一个值,但能确定相对关系,需要用到反。

         并查集的算法在这题里比2-SAT的快,剩了些不必要的计算,思想也挺巧妙的。

      1 #include <stdio.h>
      2 #include <string.h>
      3 #define N  501*32
      4 #define m1 mset.find(1)
      5 #define m0 mset.find(0)
      6 struct myset
      7 {
      8     int uset[501*64+10];
      9     myset(){init();};
     10     void init(){memset(uset,-1,sizeof uset);}
     11     int find(int k)
     12     {
     13         if (uset[k]==-1) return k;
     14         return uset[k]=find(uset[k]);
     15     }
     16     void uion(int a,int b)
     17     {
     18         int aa=find(a);
     19         int bb=find(b);
     20         if (aa==bb) return;
     21         uset[aa]=bb;
     22     }
     23 }mset;
     24 int b[501][501],n;
     25 bool solve()
     26 {
     27     for (int i=0;i<n;++i)
     28         for (int j=i;j<n;++j)
     29     {
     30         if (i==j && b[i][j]) return false;
     31         if (b[i][j]!=b[j][i]) return false;
     32     }
     33     for (int i=0;i<n;++i)
     34         for (int j=0;j<n;++j)
     35     {
     36         if (i==j) continue;
     37         if (i&1 && j&1)
     38         {
     39             for (int k=0;k<32;++k)
     40             {
     41                 if (b[i][j]&(1<<k) == 0)
     42                 {
     43                     int p1=i*32+k+2;
     44                     int p2=j*32+k+2;
     45                     if (mset.find(p1)==m1 || mset.find(p2)==m1 || mset.find(p1)==mset.find(p2+N)) return false;
     46                     mset.uion(p1,0);
     47                     mset.uion(p2,0);
     48                     mset.uion(p1+N,1);
     49                     mset.uion(p2+N,1);
     50                 }
     51             }
     52         } else
     53         if (!(i&1) && !(j&1))
     54         {
     55             for (int k=0;k<32;++k)
     56             {
     57                  if (b[i][j]&(1<<k))
     58                 {
     59                     int p1=i*32+k+2;
     60                     int p2=j*32+k+2;
     61                     if (mset.find(p1)==m0 || mset.find(p2)==m0 || mset.find(p1)==mset.find(p2+N)) return false;
     62                     mset.uion(p1,1);
     63                     mset.uion(p2,1);
     64                     mset.uion(p1+N,0);
     65                     mset.uion(p2+N,0);
     66                 }
     67             }
     68         } else
     69         {
     70              for (int k=0;k<32;++k)
     71             {
     72                   int p1=i*32+k+2;
     73                   int p2=j*32+k+2;
     74                  if (b[i][j]&(1<<k))
     75                 {
     76                     if (mset.find(p1)==mset.find(p2)) return false;
     77                     mset.uion(p1,p2+N);
     78                     mset.uion(p2,p1+N);
     79                 } else
     80                 {
     81                     if (mset.find(p1)==mset.find(p2+N) ) return false;
     82                     mset.uion(p1,p2);
     83                     mset.uion(p1+N,p2+N);
     84                 }
     85             }
     86         }
     87     }
     88     return true;
     89 }
     90 int main()
     91 {
     92     while (~scanf("%d",&n))
     93     {
     94         mset.init();
     95         for (int i=0;i<n;++i)
     96             for (int j=0;j<n;++j)
     97             scanf("%d",&b[i][j]);
     98         if (solve()) puts("YES"); else puts("NO");
     99     }
    100 }
    并查集
  • 相关阅读:
    学就要学好 就要学明白
    URL的基础
    各种waf识别
    Linux命令行上的上传和下载文件命令
    Linux服务器安全加固(三)
    Linux服务器安全加固(二)
    Linux服务器安全加固(一)
    Centos7配置SNMP服务
    Windows Server 系统通用安全基线配置详细
    Windows Server 2016 部署AD域控制器及添加AD域控制器
  • 原文地址:https://www.cnblogs.com/wuminye/p/3274609.html
Copyright © 2011-2022 走看看