拆位,每一位建一次图判断是否可行,如果一次性建完每一位的图然后跑一次2-sat会爆边。
#include <bits/stdc++.h>
using namespace std;
#define maxn 51111
#define maxm 5111111
#define index Index
int n;
long long b[511][511];
struct node {
int to, next;
}edge[maxm];
int head[maxn], cnt;
int get_pos (int i) {
return 2*(i);
}
void add_edge (int from, int to, int i) {
node &e = edge[i];
e.to = to, e.next = head[from], head[from] = i;
}
int low[maxn], dfn[maxn], s[maxn], belong[maxn];
int index, top, scc, num[maxn];
bool vis[maxn];
void tarjan (int u) {
int v;
low[u] = dfn[u] = ++index;
s[++top] = u;
vis[u] = 1;
for (int i = head[u]; i != -1; i = edge[i].next) {
v = edge[i].to;
if (!dfn[v]) {
tarjan (v);
low[u] = min (low[u], low[v]);
}
else if (vis[v])
low[u] = min (dfn[v], low[u]);
}
if (low[u] == dfn[u]) {
scc++;
do {
v = s[top--];
vis[v] = 0;
belong[v] = scc;
} while (v != u);
}
}
bool two_sat () {
memset (dfn, 0, sizeof dfn);
memset (vis, 0, sizeof vis);
memset (num, 0, sizeof num);
index = scc = top = 0;
for (int i = 0; i < n*2; i++) {
if (!dfn[i])
tarjan (i);
}
for (int i = 0; i < n*2; i += 2) {
if (belong[i] == belong[i^1])
return 0;
}
return 1;
}
void init () {
memset (head, -1, sizeof head);
cnt = 0;
}
int main () {
//freopen ("in", "r", stdin);
while (scanf ("%d", &n) == 1) {
bool ok = 1;
for (int i = 0; i < n; i++) {
for (int j = 0; j < n; j++) {
scanf ("%lld", &b[i][j]);
}
}
for (int bit = 0; bit < 31; bit++) {
init ();
for (int i = 0; i < n; i++) {
for (int j = 0; j < n; j++) {
if (i == j) {
if (b[i][j] == 0)
continue;
else {
ok = 0;
goto out;
}
}
int p = b[i][j]&(1<<bit);
int u = get_pos (i), v = get_pos (j);
if (i%2 == 0 && j%2 == 0) {
if (p) {
add_edge (u, u^1, cnt++);
add_edge (v, v^1, cnt++);
}
else {
add_edge (u^1, v, cnt++);
add_edge (v^1, u, cnt++);
}
}
else if ((i&1) && (j&1)) {
if (p) {
add_edge (u, v^1, cnt++);
add_edge (v, u^1, cnt++);
}
else {
add_edge (u^1, u, cnt++);
add_edge (v^1, v, cnt++);
}
}
else {
if (p) {
add_edge (u, v^1, cnt++);
add_edge (v, u^1, cnt++);
add_edge (u^1, v, cnt++);
add_edge (v^1, u, cnt++);
}
else {
add_edge (u^1, v^1, cnt++);
add_edge (v^1, u^1, cnt++);
add_edge (u, v, cnt++);
add_edge (v, u, cnt++);
}
}
}
}
if (two_sat ()) {
continue;
}
else {
ok = 0;
goto out;
}
}
out: ;
if (!ok) {
printf ("NO\n");
}
else printf ("YES\n");
}
return 0;
}