1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
//! 2-SAT。

use super::super::graph::scc_;

use scc_::scc;

/// 2-SAT。
///
/// $f(x\_1, \\dots, x\_n) = \\bigwedge (\\bullet \\vee \\bullet)$
/// の形の論理式を $\\top$ にするような $x\_1, \\dots, x\_n$ の割り当てがあるか判定する。
/// ただし、各々の $\\bullet$ は $x\_1, \\dots, x\_n, \\lnot x\_1, \\dots \\lnot x\_n$
/// のうちのいずれかである。
///
/// # Examples
/// ```
/// use nekolib::math::TwoSat;
///
/// let mut ts = TwoSat::new(4);
/// ts.add_clause(1, 1);
/// ts.add_clause(-2, -2);
/// ts.add_clause(3, -4);
///
/// let w = ts.witness().unwrap();
/// assert!(w[1]);
/// assert!(!w[2]);
/// assert!(w[3] || !w[4]);
///
/// ts.add_clause(-1, -1);
/// assert_eq!(ts.witness(), None);
/// ```
pub struct TwoSat {
    n: usize,
    cnf: Vec<(isize, isize)>,
}

impl TwoSat {
    /// $f(x\_1, \\dots, x\_n) = \\top$ で初期化する。
    ///
    /// # Examples
    /// ```
    /// use nekolib::math::TwoSat;
    ///
    /// let ts = TwoSat::new(1);
    /// assert!(ts.witness().is_some());
    /// ```
    pub fn new(n: usize) -> Self { Self { n, cnf: vec![] } }
    /// $f(x\_1, \\dots, x\_n) \\xleftarrow{\\wedge} (x\_i \\vee x\_j)$ で更新する。
    ///
    /// ただし、$i \\lt 0$ のとき $x\_i$ は $\\lnot x\_{-i}$ を指すとする。
    ///
    /// # Examples
    /// ```
    /// use nekolib::math::TwoSat;
    ///
    /// let mut ts = TwoSat::new(3);
    /// ts.add_clause(-1, 2);
    /// ts.add_clause(1, 3);
    /// ```
    pub fn add_clause(&mut self, i: isize, j: isize) { self.cnf.push((i, j)); }
    /// 充足可能性を判定し、可能なら解を返す。
    ///
    /// # Examples
    /// ```
    /// use nekolib::math::TwoSat;
    ///
    /// let mut ts = TwoSat::new(3);
    /// ts.add_clause(-1, 2);
    /// ts.add_clause(-2, 3);
    /// ts.add_clause(-3, -2);
    /// let w = ts.witness().unwrap();
    /// assert!(!w[1] || w[2]);
    /// assert!(!w[2] || w[3]);
    /// assert!(!w[3] || !w[2]);
    /// // w == [_, false, false, true], for example.
    ///
    /// ts.add_clause(2, 1);
    /// assert_eq!(ts.witness(), None);
    pub fn witness(&self) -> Option<Vec<bool>> {
        let n = self.n;
        let g = {
            let mut g = vec![vec![]; 2 * (n + 1)];
            for &(i, j) in &self.cnf {
                let (i, not_i) = Self::enc(i);
                let (j, not_j) = Self::enc(j);
                g[not_i].push(j);
                g[not_j].push(i);
            }
            g
        };
        let index = |&v: &usize| v;
        let delta = |&v: &usize| g[v].iter().cloned();
        let comp_id = scc(g.len(), 2..g.len(), index, delta);
        if (1..=n).any(|i| comp_id[2 * i] == comp_id[2 * i + 1]) {
            return None;
        }
        Some(
            std::iter::once(true)
                .chain((1..=n).map(|i| comp_id[2 * i + 1] < comp_id[2 * i]))
                .collect(),
        )
    }
    fn enc(i: isize) -> (usize, usize) {
        let ii = 2 * i.abs() as usize;
        if i < 0 {
            (ii + 1, ii)
        } else {
            (ii, ii + 1)
        }
    }
}