(p or q) => add edge (~p => q), (~q => p)
(p) = (p or p)
(p xor q) = (~p or ~q) and (p or q)
At least 1 of (p, q) is true: (p or q)
At least 2 of (p, q) is true: (p and q)
At least 1 of (p, q, r) is true: (p or q or r) => Not a CNF.
At least 2 of (p, q, r) is true: (p or q) and (q or r) and (p or r)
At least 3 of (p, q, r) is true: (p and q and r)
After tarjan scc,
* No solution if any p has belong[p] = belong[~p].
* p is true if belong[p] < belong[~p], i.e., topo(p) > topo(~p).
If we get a truth table, we can construct the CNF.
p q eval
- - F
- + T
+ - F
+ + T
We ban all the entries that are F. The DNF of banned entries is
(~p and ~q) or (p and ~q)
Negate the DNF and we get CNF of the T entries:
(p or q) and (~p or q)
let mut add_clause = |p: usize, q: usize| {
adj[p ^ 1].push(q);
adj[q ^ 1].push(p);
};
// Check contradiction
let ok = (0..n).all(|i| belong[2 * i] != belong[2 * i ^ 1]);
// Solution
for i in 0..n {
let pos_i = 2 * i;
if belong[pos_i] < belong[pos_i ^ 1] {
// i is positive
} else {
// i is negative
}
}