HDU 4421 & ZOJ 3556 Bit Magic(2-SAT 位运算 模板题)

来源:互联网 发布:淘宝实拍保护入口 编辑:程序博客网 时间:2024/06/06 04:25

题目链接:

ZOJ:  http://acm.zju.edu.cn/onlinejudge/showProblem.do?problemId=4879

HDU:http://acm.hdu.edu.cn/showproblem.php?pid=4421

Yesterday, my teacher taught me about bit operators: and (&), or (|), xor (^). I generated a number table a[N], and wrote a program to calculate the matrix table b[N][N] using three kinds of bit operator. I thought my achievement would get teacher's attention.

The key function is the code showed below.

void calculate(int a[N], int b[N][N]) {for (int i = 0; i < N; ++i) {for (int j = 0; j < N; ++j) {if (i == j) b[i][j] = 0;else if (i % 2 == 1 && j % 2 == 1) b[i][j] = a[i] | a[j];else if (i % 2 == 0 && j % 2 == 0) b[i][j] = a[i] & a[j];else b[i][j] = a[i] ^ a[j];}}}

There is no doubt that my teacher raised lots of interests in my work and was surprised to my talented programming skills. After deeply thinking, he came up with another problem: if we have the matrix table b[N][N] at first, can you check whether corresponding number table a[N] exists?

Input

There are multiple test cases.

For each test case, the first line contains an integer N, indicating the size of the matrix. (1 ≤ N ≤ 500).

The next N lines, each line contains N integers, the jth integer in ith line indicating the element b[i][j] of matrix. (0 ≤ b[i][j] ≤ 2 ^ 31 - 1)

Output

For each test case, output "YES" if corresponding number table a[N] exists; otherwise output "NO".

Sample Input

20 44 030 1 241 0 8624 86 0

Sample Output

YESNO


PS:

模拟栈,HDU上一直T!

代码如下:

#include <cstdio>#include <cmath>#include <cstring>#include <stack>#include <iostream>#include <algorithm>using namespace std;////And 结果为1:建边 ~x->x, ~y->y (两个数都为1)////And 结果为0:建边 y->~x , x->~y(两个数至少有一个为0)////OR  结果为1:建边 ~x->y , ~y->x(两个数至少有一个为1)////OR  结果为0:建边 x->~x , y->~y(两个数都为0)////XOR 结果为1:建边 x->~y , ~x->y , ~y->x , y -> ~x (两个数一个为0,一个为1)////XOR 结果为0:建边 x->y , ~x->~y , y->x ~y->~x(两个数同为1或者同为0)#define M 1000017#define MAXN 1017//a<<1 和 (a<<1) + 1。a<<1表示元素取0 ,(a<<1) + 1表示取 1//i 和 i+n。i表示这个元素取0,i+n表示这个元素取1//连接某边是为了推出矛盾。x->y表示选x则必须选y//注意方向int b[MAXN][MAXN];struct node{    int s, t;    int next;} e[M];int n, m;int idx, ans, tp, cont;int dfn[MAXN];//记录搜索到该点的时间,也就是第几个搜索这个点的。int low[MAXN];//标记数组,记录该点所在的强连通子图所在搜索子树的根节点的dfn值。int st[MAXN],belong[MAXN];//记录每个点属于哪一个强连通分量。int vis[MAXN],head[MAXN];int num = 0;//强连通分量个数stack< int >s;bool instack[MAXN];//是否在栈中void add(int s,int t){    e[cont].s = s;//有时候不注释掉会T    e[cont].t = t;    e[cont].next = head[s];    head[s] = cont++;}void build_grap(int status)//建图{    for(int i = 0 ; i < n ; ++i)    {        for(int j = 0 ; j < n ; ++j)        {            if(i == j)                continue;            if(i%2 == 0 && j%2 == 0)//a & b            {                if(b[i][j] & (1<<status))                {                    //a&b == 1  --->> (a==1 && b==1) && (a!=0 && b!=0)                    add((i<<1), (i<<1)+1), add((j<<1), (j<<1)+1);// a!= 0 && b != 0                    add((i<<1)+1, (j<<1)+1), add((j<<1)+1, (i<<1)+1);//a == 1 && b ==1                }                else//a&b == 0  --->> (a==1 &&  b==0) || (b==1 && a==0)                {                    //注意方向 是选了1才必须选0  不是选0才必须选1                    add((i<<1)+1, (j<<1));                    add((j<<1)+1, (i<<1));                }            }            else if(i%2 == 1 && j%2 == 1) //a | b            {                if(b[i][j] & (1<<status))// b[i][j]=1                {                    //(a==1 && b==1) || (a==0 && b==1) || (a==1 && b==0)                    add((i<<1), (j<<1)+1);//a选0,b只能选1才能满足a|b==1,b选0时a也只能选1                    add((j<<1), (i<<1)+1);                }                else// a==0  b==0  ; a!=1 ; b!=1                {                    add((i<<1), (j<<1)), add((j<<1), (i<<1));                    add((i<<1)+1, (i<<1)), add((j<<1)+1, (i<<1));//注意方向,先后关系                }            }            else//a^b            {                if(b[i][j] & (1<<status))                {                    //(a==1 && b==0) ||  (a==0 && b==1)                    add((i<<1)+1, (j<<1)), add((j<<1), (i<<1)+1);//a==1 && b==0                    add((j<<1)+1, (i<<1)), add((i<<1), (j<<1)+1);//a==0 && b==1                }                else// (a==1 && b==1) ||  (a==0 && b==0)                {                    add((i<<1), (j<<1)), add((j<<1), (i<<1));                    add((i<<1)+1, (j<<1)+1), add((j<<1)+1, (i<<1)+1);//注意方向                }            }        }    }}void tarjan(int u)//求强连通分量(模版){    int i;    dfn[u]=low[u]=++idx;    s.push(u);    instack[u]=true;    int v;    for(i = head[u]; i!=-1; i = e[i].next)    {        v = e[i].t;        if(!dfn[v])        {            tarjan(v);            low[u]=min(low[u],low[v]);        }        else if(instack[v])low[u]=min(low[u],dfn[v]);    }    if(dfn[u]==low[u])    {        num++;             //强连通分量个数        do        {            v=s.top();            s.pop();            belong[v]=num;   //第v个点属于第num个连通块            instack[v]=false;        }        while(u!=v);    }}//void tarjan(int u)//模拟栈//{//    dfn[u] = low[u] = ++idx;//    vis[u] = 1;//    st[++tp] = u;//    int v ;//    for(int i = head[u]; i != -1; i = e[i].next)//    {//        v = e[i].t ;//        if(!dfn[v])//        {//            tarjan(v) ;//            low[u] = min(low[u],low[v]);//        }//        else if(vis[v])//            low[u] = min(low[u],dfn[v]);//    }//    if(dfn[u] == low[u])//    {//        ans++;//        while(1)//        {//            v = st[tp--];//            vis[v] = 0;//            belong[v] = ans;//            if(v == u)//                break;//        }//    }//}bool _2sat(){    memset(vis,0,sizeof(vis));    memset(dfn,0,sizeof(dfn));    idx = tp = ans = num = 0;    for(int i = 0; i < 2*n; i++)        if(!dfn[i])            tarjan(i) ;    for(int i = 0; i < n; i++)        if(belong[2*i] == belong[(2*i)^1])//矛盾            return false ;    return true;}int main(){    while(~scanf("%d",&n))    {        for(int i = 0; i < n; i++)            for(int j = 0; j < n; j++)                scanf("%d",&b[i][j]);        int flag = 0;        for(int i = 0; i < n; i++) //b[i][i]为零        {            if(b[i][i] != 0)            {                flag = 1;                break;            }        }        if(flag)        {            printf("NO\n");            continue;        }        flag = 1;        for(int i = 0 ; i <= 31 ; ++i)//二进制位        {            cont = 0;            memset(head,-1,sizeof(head));            build_grap(i);            if(!_2sat())//矛盾            {                flag = 0;                break;            }        }        if(!flag)printf("NO\n");        else printf("YES\n");    }    return 0;}


1 0
原创粉丝点击