Skip to content

Commit fc680ae

Browse files
committed
Add document for twosat
1 parent 19509cd commit fc680ae

File tree

1 file changed

+87
-0
lines changed

1 file changed

+87
-0
lines changed

src/twosat.rs

Lines changed: 87 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,23 +1,99 @@
1+
//! A 2-SAT Solver.
12
use crate::internal_scc;
23

4+
/// A 2-SAT Solver.
5+
///
6+
/// For variables $x_0, x_1, \ldots, x_{N - 1}$ and clauses with from
7+
///
8+
/// \\[
9+
/// (x_i = f) \lor (x_j = g)
10+
/// \\]
11+
///
12+
/// it decides whether there is a truth assignment that satisfies all clauses.
13+
///
14+
/// # Example
15+
///
16+
/// ```
17+
/// #![allow(clippy::many_single_char_names)]
18+
///
19+
/// use ac_library_rs::TwoSat;
20+
/// use proconio::{input, marker::Bytes, source::once::OnceSource};
21+
///
22+
/// input! {
23+
/// from OnceSource::from(
24+
/// "3\n\
25+
/// 3\n\
26+
/// a b\n\
27+
/// !b c\n\
28+
/// !a !a\n",
29+
/// ),
30+
/// n: usize,
31+
/// pqs: [(Bytes, Bytes)],
32+
/// }
33+
///
34+
/// let mut twosat = TwoSat::new(n);
35+
///
36+
/// for (p, q) in pqs {
37+
/// fn parse(s: &[u8]) -> (usize, bool) {
38+
/// match *s {
39+
/// [c] => ((c - b'a').into(), true),
40+
/// [b'!', c] => ((c - b'a').into(), false),
41+
/// _ => unreachable!(),
42+
/// }
43+
/// }
44+
/// let ((i, f), (j, g)) = (parse(&p), parse(&q));
45+
/// twosat.add_clause(i, f, j, g);
46+
/// }
47+
///
48+
/// assert!(twosat.satisfiable());
49+
/// assert_eq!(twosat.answer(), [false, true, true]);
50+
/// ```
351
pub struct TwoSat {
452
n: usize,
553
scc: internal_scc::SccGraph,
654
answer: Vec<bool>,
755
}
856
impl TwoSat {
57+
/// Creates a new `TwoSat` of `n` variables and 0 clause.
58+
///
59+
/// # Constraints
60+
///
61+
/// - $0 \leq n \leq 10^8$
62+
///
63+
/// # Complexity
64+
///
65+
/// - $O(n)$
966
pub fn new(n: usize) -> Self {
1067
TwoSat {
1168
n,
1269
answer: vec![false; n],
1370
scc: internal_scc::SccGraph::new(2 * n),
1471
}
1572
}
73+
/// Adds a clause $(x_i = f) \lor (x_j = g)$.
74+
///
75+
/// # Constraints
76+
///
77+
/// - $0 \leq i < n$
78+
/// - $0 \leq j < n$
79+
///
80+
/// # Panics
81+
///
82+
/// Panics if the above constraints are not satisfied.
83+
///
84+
/// # Complexity
85+
///
86+
/// - $O(1)$ amortized
1687
pub fn add_clause(&mut self, i: usize, f: bool, j: usize, g: bool) {
1788
assert!(i < self.n && j < self.n);
1889
self.scc.add_edge(2 * i + !f as usize, 2 * j + g as usize);
1990
self.scc.add_edge(2 * j + !g as usize, 2 * i + f as usize);
2091
}
92+
/// Returns whether there is a truth assignment that satisfies all clauses.
93+
///
94+
/// # Complexity
95+
///
96+
/// - $O(n + m)$ where $m$ is the number of added clauses
2197
pub fn satisfiable(&mut self) -> bool {
2298
let id = self.scc.scc_ids().1;
2399
for i in 0..self.n {
@@ -28,6 +104,17 @@ impl TwoSat {
28104
}
29105
true
30106
}
107+
/// Returns a truth assignment that satisfies all clauses **of the last call of [`satisfiable`]**.
108+
///
109+
/// # Constraints
110+
///
111+
/// - [`satisfiable`] is called after adding all clauses and it has returned `true`.
112+
///
113+
/// # Complexity
114+
///
115+
/// - $O(n)$
116+
///
117+
/// [`satisfiable`]: #method.satisfiable
31118
pub fn answer(&self) -> &[bool] {
32119
&self.answer
33120
}

0 commit comments

Comments
 (0)