use std::collections::{HashMap, HashSet};
struct Candidate {
beats: HashSet<u32>,
beaten: HashSet<u32>,
}
impl Candidate {
fn new() -> Candidate {
Candidate {
beats: HashSet::new(),
beaten: HashSet::new(),
}
}
}
pub struct ForcedDag {
graph: HashMap<u32, Candidate>,
n2i: Vec<u32>,
}
impl ForcedDag {
pub fn new(candidates: u32) -> ForcedDag {
ForcedDag {
graph: (0..candidates).map(|c| (c, Candidate::new())).collect(),
n2i: (0..candidates).collect(),
}
}
fn dfs(
&self,
v: u32,
lim: u32,
r: &mut Option<Vec<u32>>,
visited: &mut HashSet<u32>,
fwd: bool,
) -> bool {
if let Some(x) = r.as_mut() {
x.push(v);
}
visited.insert(v);
if let Some(vv) = self.graph.get(&v) {
let next = if fwd { &vv.beats } else { &vv.beaten };
for vn in next {
if self.n2i[*vn as usize] == lim {
return false;
}
if !visited.contains(vn)
&& self.n2i[*vn as usize] < lim
&& !self.dfs(*vn, lim, r, visited, fwd)
{
return false;
}
}
}; true
}
pub fn add_edge(&mut self, f: u32, t: u32) -> bool {
let upper = self.n2i[f as usize]; let lower = self.n2i[t as usize]; if lower < upper {
let mut visited = HashSet::new();
let mut rf: Option<Vec<u32>> = Some(Vec::new());
if !self.dfs(t, upper, &mut rf, &mut visited, true) {
return false;
}
let mut rb: Option<Vec<u32>> = Some(Vec::new());
if !self.dfs(f, lower, &mut rb, &mut visited, false) {
return false;
}
let mut rf = rf.unwrap();
rf.sort_unstable_by(|&a, &b| self.n2i[a as usize].cmp(&self.n2i[b as usize]));
let mut rb = rb.unwrap();
rb.sort_unstable_by(|&a, &b| self.n2i[a as usize].cmp(&self.n2i[b as usize]));
let to_realloc: Vec<u32> = rb.iter().chain(rf.iter()).cloned().collect();
let mut idx_we_have: Vec<u32> =
to_realloc.iter().map(|&x| self.n2i[x as usize]).collect();
idx_we_have.sort_unstable();
for (e, into) in to_realloc.iter().zip(idx_we_have) {
self.n2i[*e as usize] = into
}
}
self.graph.get_mut(&f).unwrap().beats.insert(t);
self.graph.get_mut(&t).unwrap().beaten.insert(f);
true
}
pub fn try_edge(&self, f: u32, t: u32) -> bool {
let upper = self.n2i[f as usize]; let lower = self.n2i[t as usize]; lower > upper || {
let mut visited = HashSet::new();
self.dfs(t, upper, &mut None, &mut visited, true)
&& self.dfs(f, lower, &mut None, &mut visited, false)
}
}
pub fn get_winner(&self) -> Result<u32, ()> {
let mut winners = self.graph.iter().filter_map(|(&cid, cand)| {
if cand.beaten.is_empty() {
Some(cid)
} else {
None
}
});
if let Some(winner) = winners.next() {
if winners.next().is_none() {
Ok(winner)
} else {
Err(())
}
} else {
Err(())
}
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn basic() {
let mut fd = ForcedDag::new(6);
assert!(fd.add_edge(0, 1));
assert!(fd.add_edge(2, 3));
assert!(fd.add_edge(4, 5));
assert!(fd.add_edge(0, 2));
assert!(fd.add_edge(1, 3));
assert!(fd.add_edge(4, 0));
assert!(fd.add_edge(5, 1));
assert!(!fd.add_edge(2, 4));
assert!(fd.add_edge(2, 5));
}
}