nekolib/math/two_sat.rs
1//! 2-SAT。
2
3use super::super::graph::scc_;
4
5use scc_::scc;
6
7/// 2-SAT。
8///
9/// $f(x\_1, \\dots, x\_n) = \\bigwedge (\\bullet \\vee \\bullet)$
10/// の形の論理式を $\\top$ にするような $x\_1, \\dots, x\_n$ の割り当てがあるか判定する。
11/// ただし、各々の $\\bullet$ は $x\_1, \\dots, x\_n, \\lnot x\_1, \\dots \\lnot x\_n$
12/// のうちのいずれかである。
13///
14/// # Examples
15/// ```
16/// use nekolib::math::TwoSat;
17///
18/// let mut ts = TwoSat::new(4);
19/// ts.add_clause(1, 1);
20/// ts.add_clause(-2, -2);
21/// ts.add_clause(3, -4);
22///
23/// let w = ts.witness().unwrap();
24/// assert!(w[1]);
25/// assert!(!w[2]);
26/// assert!(w[3] || !w[4]);
27///
28/// ts.add_clause(-1, -1);
29/// assert_eq!(ts.witness(), None);
30/// ```
31pub struct TwoSat {
32 n: usize,
33 cnf: Vec<(isize, isize)>,
34}
35
36impl TwoSat {
37 /// $f(x\_1, \\dots, x\_n) = \\top$ で初期化する。
38 ///
39 /// # Examples
40 /// ```
41 /// use nekolib::math::TwoSat;
42 ///
43 /// let ts = TwoSat::new(1);
44 /// assert!(ts.witness().is_some());
45 /// ```
46 pub fn new(n: usize) -> Self { Self { n, cnf: vec![] } }
47 /// $f(x\_1, \\dots, x\_n) \\xleftarrow{\\wedge} (x\_i \\vee x\_j)$ で更新する。
48 ///
49 /// ただし、$i \\lt 0$ のとき $x\_i$ は $\\lnot x\_{-i}$ を指すとする。
50 ///
51 /// # Examples
52 /// ```
53 /// use nekolib::math::TwoSat;
54 ///
55 /// let mut ts = TwoSat::new(3);
56 /// ts.add_clause(-1, 2);
57 /// ts.add_clause(1, 3);
58 /// ```
59 pub fn add_clause(&mut self, i: isize, j: isize) { self.cnf.push((i, j)); }
60 /// 充足可能性を判定し、可能なら解を返す。
61 ///
62 /// # Examples
63 /// ```
64 /// use nekolib::math::TwoSat;
65 ///
66 /// let mut ts = TwoSat::new(3);
67 /// ts.add_clause(-1, 2);
68 /// ts.add_clause(-2, 3);
69 /// ts.add_clause(-3, -2);
70 /// let w = ts.witness().unwrap();
71 /// assert!(!w[1] || w[2]);
72 /// assert!(!w[2] || w[3]);
73 /// assert!(!w[3] || !w[2]);
74 /// // w == [_, false, false, true], for example.
75 ///
76 /// ts.add_clause(2, 1);
77 /// assert_eq!(ts.witness(), None);
78 pub fn witness(&self) -> Option<Vec<bool>> {
79 let n = self.n;
80 let g = {
81 let mut g = vec![vec![]; 2 * (n + 1)];
82 for &(i, j) in &self.cnf {
83 let (i, not_i) = Self::enc(i);
84 let (j, not_j) = Self::enc(j);
85 g[not_i].push(j);
86 g[not_j].push(i);
87 }
88 g
89 };
90 let index = |&v: &usize| v;
91 let delta = |&v: &usize| g[v].iter().cloned();
92 let comp_id = scc(g.len(), 2..g.len(), index, delta);
93 if (1..=n).any(|i| comp_id[2 * i] == comp_id[2 * i + 1]) {
94 return None;
95 }
96 Some(
97 std::iter::once(true)
98 .chain((1..=n).map(|i| comp_id[2 * i + 1] < comp_id[2 * i]))
99 .collect(),
100 )
101 }
102 fn enc(i: isize) -> (usize, usize) {
103 let ii = 2 * i.abs() as usize;
104 if i < 0 {
105 (ii + 1, ii)
106 } else {
107 (ii, ii + 1)
108 }
109 }
110}