ZOJ_3656_Bit Magic(2-SAT)

Bit Magic
Time Limit:8000MS    Memory Limit:32768KB    64bit IO Format:%lld & %llu

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.

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

2
0 4
4 0
3
0 1 24
1 0 86
24 86 0

Sample Output

YES

NO


题意:给出一个calculate函数,再给出b数组,问a数组是否存在。


分析:2-SAT问题。一开始,想到把每个a[i]转化成31位二进制,也就是相当于把每个a[i]拆成31个点,然后去建图。

然而这样子却一直MLE。思路也就止于此。然后看了下别人的题解,发现思路是差不多的。但是他是跑31次2-SAT

来判断,也就是对每个a[i]的每一位拿出来,判断31次如果都满足即可输出YES,否则输出NO。


题目链接:http://acm.zju.edu.cn/onlinejudge/showProblem.do?problemCode=3656


代码清单:

#include <set>
#include <map>
#include <cmath>
#include <stack>
#include <queue>
#include <ctime>
#include <cctype>
#include <string>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <iostream>
#include <algorithm>
using namespace std;

typedef long long ll;
typedef unsigned int uint;
typedef unsigned long long ull;

const int maxN = 500 + 5;
const int maxn = 2000 + 5;

int N, n;
int tmap[maxN][maxN];

int dfn[maxn];          //深度优先访问次序
int low[maxn];          //能追溯到的最早次序
int belong[maxn];       //点的属于哪个强连通分量
vector <int> graph[maxn]; //邻接表存图
stack <int> sta;          //存储已遍历的节点
bool InStack[maxn];     //是否在栈中
int _index;             //索引号
int sccno;              //强连通分量个数

void init(){     //初始化
    memset(dfn, 0, sizeof(dfn));
    memset(low, 0, sizeof(low));
    memset(belong, 0, sizeof(belong));
    memset(InStack, false, sizeof(InStack));
    for(int i = 0; i < 2 * n; i++){
        graph[i].clear();
    }
    while(!sta.empty()) sta.pop();
    _index = 0;
    sccno = 0;
}

void input(){ //输入
    for(int i = 0; i < N; i++){
        for(int j = 0; j < N; j++){
            scanf("%d", &tmap[i][j]);
        }
    }
}

void createGraph(int k){
    for(int i = 0; i < N; i++){
        for(int j = 0; j < i; j++){
            if(i % 2 == 1 && j % 2 == 1){ // a[i] | a[j] 
                if((1 << k) & tmap[i][j]){
                    graph[i + n].push_back(j);
                    graph[j + n].push_back(i);
                }
                else{
                    graph[i + n].push_back(j + n);
                    graph[j + n].push_back(i + n);
                }
            }
            else if(i % 2 == 0 && j % 2 == 0){ // a[i] & a[j]
                if((1 << k) & tmap[i][j]){
                    graph[i + n].push_back(i);
                    graph[j + n].push_back(j);
                    //graph[i].push_back(j);
                    //graph[j].push_back(i);
                }
                else{
                    graph[i].push_back(j + n);
                    graph[j].push_back(i + n);
                }
            }
            else{ // a[i] ^ a[j]
                if((1 << k) & tmap[i][j]){
                    graph[i].push_back(j + n);
                    graph[i + n].push_back(j);
                    graph[j].push_back(i + n);
                    graph[j + n].push_back(i);
                }
                else{
                    graph[i].push_back(j);
                    graph[j].push_back(i);
                    graph[i + n].push_back(j + n);
                    graph[j + n].push_back(i + n);
                }
            }
        }
    }
}


void tarjan(int u){   //强连通分量
    dfn[u] = low[u] = ++_index;
    sta.push(u);
    InStack[u] = true;
    for(int i = 0; i < graph[u].size(); i++){
        int v = graph[u][i];
        if(!dfn[v]){
            tarjan(v);
            low[u] = min(low[u], low[v]);
        }
        if(InStack[v]){
            low[u] = min(low[u], dfn[v]);
        }
    }
    if(dfn[u] == low[u]){
        sccno++;
        while(!sta.empty()){
            int j = sta.top();
            sta.pop();
            InStack[j] = false;
            belong[j] = sccno;   
            if(j == u) break;
        }
    }
}

void findscc(){
    for(int u = 0; u < 2 * n; u++){
        if(!dfn[u]) tarjan(u);
    }
}

bool exitSolution(){   //是否有解
    for(int u = 0; u < n; u++){
        if(belong[u] == belong[u + n])
            return false;
    }
    return true;
}

void solve(){
    for(int i = 0; i < N; i++){
        for(int j = 0; j <= i; j++){
            if(i == j && tmap[i][j] != 0){ //容易WA在这
                puts("NO");
                return ;
            }
            if(tmap[i][j] != tmap[j][i]){
                puts("NO");
                return ;
            }
        }
    }
    n = N;
    for(int k = 0; k < 31; k++){
        init();
        createGraph(k);
        findscc();
        if(!exitSolution()){
            puts("NO");
            return ;
        }
    }
    puts("YES");
    return ;

}

int main(){
    while(scanf("%d", &N) != EOF){
        input();
        solve();
    }return 0;
}



  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值