拆位,每一位建一次图判断是否可行,如果一次性建完每一位的图然后跑一次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; }