Skip to content

Commit c0fdb21

Browse files
add two-sat (#41)
* add two-sat * fix clippy * fix doctest
1 parent b1f4b09 commit c0fdb21

File tree

4 files changed

+116
-0
lines changed

4 files changed

+116
-0
lines changed

Cargo.toml

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -70,6 +70,10 @@ path = "examples/graphs/lca_yosupo.rs"
7070
name = "scc"
7171
path = "examples/graphs/scc.rs"
7272

73+
[[example]]
74+
name = "two_sat"
75+
path = "examples/graphs/two_sat.rs"
76+
7377
[[example]]
7478
name = "binom"
7579
path = "examples/numbers/binom.rs"

examples/graphs/two_sat.rs

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
// verification-helper: PROBLEM https://judge.yosupo.jp/problem/two_sat
2+
3+
use proconio::input;
4+
use programming_team_code_rust::graphs::two_sat::TwoSat;
5+
6+
fn main() {
7+
input! {
8+
_p: String,
9+
_cnf: String,
10+
n: usize,
11+
m: usize,
12+
clauses: [(i32, i32, usize); m],
13+
}
14+
15+
let mut ts = TwoSat::new(n);
16+
17+
for (x, y, _) in clauses {
18+
let f = x > 0;
19+
let g = y > 0;
20+
ts.add_clause(
21+
x.unsigned_abs() as usize - 1,
22+
f,
23+
y.unsigned_abs() as usize - 1,
24+
g,
25+
);
26+
}
27+
28+
let ans = ts.solve();
29+
30+
if let Some(ans) = ans {
31+
println!("s SATISFIABLE");
32+
print!("v");
33+
for i in 1..=n {
34+
print!(" {}", if ans[i - 1] { i as i32 } else { -(i as i32) });
35+
}
36+
println!(" 0");
37+
} else {
38+
println!("s UNSATISFIABLE");
39+
}
40+
}

src/graphs/mod.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,3 +5,4 @@ mod dfs_order;
55
pub mod dijk;
66
pub mod lca;
77
pub mod scc;
8+
pub mod two_sat;

src/graphs/two_sat.rs

Lines changed: 71 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,71 @@
1+
//! # Two Satisfiability
2+
3+
use crate::graphs::scc::get_sccs;
4+
5+
/// # Example
6+
/// ```
7+
/// use programming_team_code_rust::graphs::two_sat::TwoSat;
8+
///
9+
/// let mut ts = TwoSat::new(2);
10+
/// ts.add_var();
11+
/// ts.add_clause(0, false, 1, true);
12+
/// ts.add_clause(1, false, 2, true);
13+
/// ts.add_clause(2, false, 0, true);
14+
/// assert_eq!(ts.solve(), Some(vec![false, false, false]));
15+
/// ```
16+
pub struct TwoSat {
17+
adj: Vec<Vec<usize>>,
18+
}
19+
20+
impl TwoSat {
21+
/// Create a new instance of TwoSat
22+
///
23+
/// # Complexity
24+
/// - Time: O(n)
25+
/// - Space: O(n)
26+
pub fn new(n: usize) -> Self {
27+
Self {
28+
adj: vec![vec![]; 2 * n],
29+
}
30+
}
31+
32+
/// Add a new variable
33+
///
34+
/// # Complexity
35+
/// - Time: O(1)
36+
/// - Space: O(1)
37+
pub fn add_var(&mut self) {
38+
self.adj.push(vec![]);
39+
self.adj.push(vec![]);
40+
}
41+
42+
/// Add a clause to the 2-SAT instance
43+
///
44+
/// # Complexity
45+
/// - Time: O(1)
46+
/// - Space: O(1)
47+
pub fn add_clause(&mut self, i: usize, f: bool, j: usize, g: bool) {
48+
self.adj[2 * i + !f as usize].push(2 * j + g as usize);
49+
self.adj[2 * j + !g as usize].push(2 * i + f as usize);
50+
}
51+
52+
/// Solve the 2-SAT instance
53+
/// Returns None if there is no solution, otherwise returns a valid assignment
54+
///
55+
/// # Complexity
56+
/// - Time: O(n)
57+
/// - Space: O(n)
58+
pub fn solve(&self) -> Option<Vec<bool>> {
59+
let (_, scc_id) = get_sccs(&self.adj);
60+
let mut res = vec![false; self.adj.len() / 2];
61+
for i in 0..self.adj.len() / 2 {
62+
if scc_id[2 * i] == scc_id[2 * i + 1] {
63+
return None;
64+
}
65+
res[i] = scc_id[2 * i] < scc_id[2 * i + 1];
66+
}
67+
Some(res)
68+
}
69+
70+
// TODO: implement this https://github.com/kth-competitive-programming/kactl/blob/main/content/graph/2sat.h#L43-L54
71+
}

0 commit comments

Comments
 (0)