Initial commit
This commit is contained in:
commit
68bfda7077
13 changed files with 4952 additions and 0 deletions
71
vertex_cover/src/filtered.rs
Normal file
71
vertex_cover/src/filtered.rs
Normal file
|
|
@ -0,0 +1,71 @@
|
|||
use crate::Graph;
|
||||
use std::collections::HashSet;
|
||||
|
||||
pub fn binary_edge(graph: &Graph, k: u16, v: HashSet<u16>) -> Option<HashSet<u16>> {
|
||||
let edge = match graph.get_edge_filtered(&v) {
|
||||
Some(edge) => edge,
|
||||
None => return Some(v),
|
||||
};
|
||||
|
||||
if k == 0 {
|
||||
return None;
|
||||
}
|
||||
|
||||
let mut v1 = v.clone();
|
||||
v1.insert(edge.0);
|
||||
match binary_edge(graph, k - 1, v1) {
|
||||
Some(s) => Some(s),
|
||||
None => {
|
||||
let mut v2 = v;
|
||||
v2.insert(edge.1);
|
||||
binary_edge(graph, k - 1, v2)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn binary_vertex(graph: &Graph, k: u16, v: HashSet<u16>) -> Option<HashSet<u16>> {
|
||||
let vertex = match graph.get_vertex_filtered_with_degree_grater(&v, 2) {
|
||||
Some(vertex) => vertex,
|
||||
None => {
|
||||
return {
|
||||
let mut v3 = v;
|
||||
let mut c = 0;
|
||||
while let Some(vertex) = graph.get_vertex_filtered_with_degree_grater(&v3, 1) {
|
||||
v3.insert(vertex);
|
||||
c += 1;
|
||||
}
|
||||
|
||||
if c <= k {
|
||||
Some(v3)
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
if k == 0 {
|
||||
return None;
|
||||
}
|
||||
|
||||
let mut v1 = v.clone();
|
||||
v1.insert(vertex);
|
||||
match binary_vertex(graph, k - 1, v1) {
|
||||
Some(s) => Some(s),
|
||||
None => {
|
||||
let mut v2 = v;
|
||||
let mut c = 0;
|
||||
for o in graph.get_edges(vertex) {
|
||||
if !v2.contains(&o) {
|
||||
c += 1;
|
||||
v2.insert(o);
|
||||
}
|
||||
}
|
||||
if c <= k {
|
||||
binary_vertex(graph, k - c, v2)
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
162
vertex_cover/src/main.rs
Normal file
162
vertex_cover/src/main.rs
Normal file
|
|
@ -0,0 +1,162 @@
|
|||
use clap::{Parser, ValueEnum};
|
||||
use std::{
|
||||
collections::HashSet,
|
||||
path::{Path, PathBuf},
|
||||
};
|
||||
|
||||
mod filtered;
|
||||
|
||||
fn parse(filename: impl AsRef<Path>) -> Graph {
|
||||
let content = std::fs::read_to_string(filename).unwrap();
|
||||
|
||||
let mut line_iter = content
|
||||
.split('\n')
|
||||
.map(|l| l.trim())
|
||||
.filter(|l| !l.is_empty());
|
||||
|
||||
let first_line = line_iter.next().unwrap();
|
||||
|
||||
let (nodes_str, edges_str) = first_line.split_once(' ').unwrap();
|
||||
|
||||
let nodes = nodes_str.parse::<u16>().unwrap();
|
||||
let edges = edges_str.parse::<u16>().unwrap();
|
||||
|
||||
let mut g = Graph::new(nodes);
|
||||
|
||||
let mut c = 0;
|
||||
for l in line_iter {
|
||||
let (from_str, to_str) = l.split_once(' ').unwrap();
|
||||
let from = from_str.parse::<u16>().unwrap();
|
||||
let to = to_str.parse::<u16>().unwrap();
|
||||
|
||||
g.add_edge(from - 1, to - 1);
|
||||
c += 1;
|
||||
}
|
||||
assert_eq!(edges, c);
|
||||
|
||||
g
|
||||
}
|
||||
|
||||
/// Datastructure is 0 indexed
|
||||
#[derive(Debug)]
|
||||
struct Graph {
|
||||
edge_list: Vec<Vec<u16>>,
|
||||
}
|
||||
|
||||
impl Graph {
|
||||
fn new(num_vertices: u16) -> Self {
|
||||
Self {
|
||||
edge_list: vec![Vec::new(); num_vertices as usize],
|
||||
}
|
||||
}
|
||||
|
||||
fn add_edge(&mut self, from: u16, to: u16) {
|
||||
self.edge_list[(from) as usize].push(to);
|
||||
self.edge_list[(to) as usize].push(from);
|
||||
}
|
||||
|
||||
fn get_edges(&self, vertex: u16) -> impl Iterator<Item = u16> + '_ {
|
||||
self.edge_list[vertex as usize].iter().copied()
|
||||
}
|
||||
|
||||
fn iter_edges_filtered<'a>(
|
||||
&'a self,
|
||||
v: &'a HashSet<u16>,
|
||||
) -> impl Iterator<Item = (u16, u16)> + 'a {
|
||||
self.edge_list
|
||||
.iter()
|
||||
.enumerate()
|
||||
.filter(|(i, _)| !v.contains(&(*i as u16)))
|
||||
.flat_map(move |(i, s)| {
|
||||
let from = i as u16;
|
||||
s.iter().filter_map(move |&to| {
|
||||
if !v.contains(&to) && from < to {
|
||||
Some((from, to))
|
||||
} else {
|
||||
None
|
||||
}
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
fn get_edge_filtered(&self, v: &HashSet<u16>) -> Option<(u16, u16)> {
|
||||
self.iter_edges_filtered(v).next()
|
||||
}
|
||||
|
||||
fn iter_vertices_filtered_with_degree_grater<'a>(
|
||||
&'a self,
|
||||
v: &'a HashSet<u16>,
|
||||
min_degree: u16,
|
||||
) -> impl Iterator<Item = u16> + 'a {
|
||||
self.edge_list.iter().enumerate().filter_map(move |(i, s)| {
|
||||
let i = i as u16;
|
||||
if !v.contains(&i) && s.iter().filter(|&o| !v.contains(o)).count() as u16 >= min_degree
|
||||
{
|
||||
Some(i)
|
||||
} else {
|
||||
None
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
fn get_vertex_filtered_with_degree_grater(
|
||||
&self,
|
||||
v: &HashSet<u16>,
|
||||
min_degree: u16,
|
||||
) -> Option<u16> {
|
||||
self.iter_vertices_filtered_with_degree_grater(v, min_degree)
|
||||
.next()
|
||||
}
|
||||
}
|
||||
|
||||
fn vertex_cover(graph: &Graph, k: u16, method: Method) -> Option<HashSet<u16>> {
|
||||
match method {
|
||||
Method::Edge => filtered::binary_edge(graph, k, HashSet::new()),
|
||||
Method::Vertex => filtered::binary_vertex(graph, k, HashSet::new()),
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Copy, ValueEnum)]
|
||||
enum Method {
|
||||
Edge,
|
||||
Vertex,
|
||||
}
|
||||
|
||||
#[derive(Debug, Parser)]
|
||||
struct Args {
|
||||
filename: PathBuf,
|
||||
method: Method,
|
||||
k: Option<u16>,
|
||||
}
|
||||
|
||||
fn main() {
|
||||
let args = Args::parse();
|
||||
|
||||
let graph = parse(args.filename);
|
||||
|
||||
let result = if let Some(k) = args.k {
|
||||
let start = std::time::Instant::now();
|
||||
let r = vertex_cover(&graph, k, args.method);
|
||||
eprintln!("{}: {:?}", k, start.elapsed());
|
||||
r
|
||||
} else {
|
||||
let mut k = 0;
|
||||
loop {
|
||||
let start = std::time::Instant::now();
|
||||
let r = vertex_cover(&graph, k, args.method);
|
||||
eprintln!("{}: {:?}", k, start.elapsed());
|
||||
if let Some(r) = r {
|
||||
break Some(r);
|
||||
}
|
||||
k += 1;
|
||||
}
|
||||
};
|
||||
|
||||
if let Some(solution) = result {
|
||||
println!("{}", solution.len());
|
||||
|
||||
for n in solution {
|
||||
println!("{}", n + 1);
|
||||
}
|
||||
}
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue