HDU 4421 Bit Magic(2-SAT)

87 篇文章 0 订阅

Bit Magic

Time Limit: 4000/2000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)
Total Submission(s): 3421    Accepted Submission(s): 959


Problem Description
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.

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
  
  
2 0 4 4 0 3 0 1 24 1 0 86 24 86 0
 

Sample Output
  
  
YES NO
 

Source
 

Recommend
zhuyuanchen520
 

题目大意:

    给一个有一个N维向量通过一定的逻辑运算得到的矩阵,问存在不存在一个N维向量满足要求。


解题思路:

    一看到给出逻辑运算结果,求存在不存在,马上就能想到时2-SAT。

    不过这里的每个元素都是整数,而不是布尔类型,我们就可以把正数看做一个二进制序列,这样每一位都是布尔类型了。由于每一位之间时完全独立的,我们就可以通过一个循环,每次只对一位执行2-SAT,而不必同时把所有位都放到一张图中(如果这样做会MLE)。然后如果每次2-SAT都有解,那么整个矩阵有解。

    附上一张从大佬的博客截过来的2-SAT逻辑运算转化表:



AC代码:

#include <iostream>
#include <algorithm>
#include <cstdio>
#include <cstring>
#include <vector>
#include <queue>
#include <stack>
#include <cstdlib>
#include <cmath>
#include <ctime>
#include <map>
#include <string>
#include <set>
using namespace std;
#define INF 0x3f3f3f3f
#define LL long long
#define fi first
#define se second
#define mem(a,b) memset((a),(b),sizeof(a))
#pragma #pragma comment(linker, "/STACK:1024000000,1024000000") 

const int MAXN=500+3;
const int MAXV=MAXN*2;
int N,V;
vector<int> G[MAXV],rG[MAXV];
vector<int> vs;
int save[MAXN][MAXN];
bool used[MAXV];
int cmp[MAXV];

void init()//初始化
{
    for(int i=0;i<2*N;++i)
    {
        G[i].clear();
        rG[i].clear();
    }
}

void dfs(int v)//正向dfs
{
    used[v]=true;
    for(int i=0;i<G[v].size();++i)
        if(!used[G[v][i]])
            dfs(G[v][i]);
    vs.push_back(v);
}

void rdfs(int v,int k)//反向dfs
{
    used[v]=true;
    cmp[v]=k;
    for(int i=0;i<rG[v].size();++i)
        if(!used[rG[v][i]])
            rdfs(rG[v][i],k);
}

int scc()//Kosaraju算法求强连通分量
{
    mem(used,0);
    vs.clear();
    for(int v=0;v<V;++v)
        if(!used[v])
            dfs(v);
    mem(used,0);
    int k=0;
    for(int i=vs.size()-1;i>=0;--i)
        if(!used[vs[i]])
            rdfs(vs[i],k++);
    return k;
}

int main()
{
    while(~scanf("%d",&N))
    {
        bool ans=true;
        for(int i=0;i<N;++i)
            for(int j=0;j<N;++j)
            {
                scanf("%d",&save[i][j]);
                if(i==j&&save[i][j]!=0)
                    ans=false;
                if(i>j&&save[i][j]!=save[j][i])
                    ans=false;
            }
        V=N*2;
        for(int i=0;i<32;++i)//每一位分开处理
        {
            init();
            bool ok=true;
            for(int i=0;i<N;++i)
                for(int j=i+1;j<N;++j)
                {
                    if((i&1)&&(j&1))//or
                    {
                        if(save[i][j]&1)
                        {
                            G[i+N].push_back(j);
                            G[j+N].push_back(i);
                            rG[j].push_back(i+N);
                            rG[i].push_back(j+N);
                        }
                        else
                        {
                            G[i].push_back(i+N);
                            G[j].push_back(j+N);
                            rG[i+N].push_back(i);
                            rG[j+N].push_back(j);
                        }
                    }
                    else if(i%2==0&&j%2==0)//and
                    {
                        if(save[i][j]&1)
                        {
                            G[i+N].push_back(i);
                            G[j+N].push_back(j);
                            rG[i].push_back(i+N);
                            rG[j].push_back(j+N);
                        }
                        else
                        {
                            G[i].push_back(j+N);
                            G[j].push_back(i+N);
                            rG[j+N].push_back(i);
                            rG[i+N].push_back(j);
                        }
                    }
                    else//xor
                    {
                        if(save[i][j]&1)
                        {
                            G[i].push_back(j+N);
                            G[j+N].push_back(i);
                            G[i+N].push_back(j);
                            G[j].push_back(i+N);
                            rG[j+N].push_back(i);
                            rG[i].push_back(j+N);
                            rG[j].push_back(i+N);
                            rG[i+N].push_back(j);
                        }
                        else
                        {
                            G[i].push_back(j);
                            G[j].push_back(i);
                            G[i+N].push_back(j+N);
                            G[j+N].push_back(i+N);
                            rG[j].push_back(i);
                            rG[i].push_back(j);
                            rG[j+N].push_back(i+N);
                            rG[i+N].push_back(j+N);
                        }
                    }
                    
                }
            scc();
            for(int i=0;i<N;++i)
                if(cmp[i]==cmp[i+N])
                {
                    ok=false;
                    break;
                }
            if(!ok)
            {
                ans=false;
                break;
            }
            for(int i=0;i<N;++i)
                for(int j=0;j<N;++j)
                    save[i][j]>>=1;
        }
        puts(ans?"YES":"NO");
    }
    
    return 0;
}


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值