Řešení KSP úlohy 33-3-4 Obsazování území
https://ksp.mff.cuni.cz/h/ulohy/33/zadani3.html#task-33-3-4
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
162 lines
5.7 KiB
162 lines
5.7 KiB
use crate::city::House;
|
|
use rusqlite::{Connection, NO_PARAMS, params, Result};
|
|
use std::collections::HashMap;
|
|
|
|
pub struct LayoutDB {
|
|
connection: Connection,
|
|
layouts: Vec<SavedLayout>,
|
|
merge_lower_bounds: HashMap<(usize, usize, bool), MergeLowerBound>,
|
|
}
|
|
|
|
pub struct MergeLowerBound {
|
|
left_layout_id: usize,
|
|
right_layout_id: usize,
|
|
y_axis: bool,
|
|
price: u32,
|
|
}
|
|
|
|
impl MergeLowerBound {
|
|
pub fn new(left_layout_id: usize, right_layout_id: usize, y_axis: bool, price: u32) -> Self {
|
|
MergeLowerBound { left_layout_id, right_layout_id, y_axis, price }
|
|
}
|
|
|
|
pub fn left_layout_id(&self) -> usize {
|
|
self.left_layout_id
|
|
}
|
|
|
|
pub fn right_layout_id(&self) -> usize {
|
|
self.right_layout_id
|
|
}
|
|
|
|
pub fn y_axis(&self) -> bool {
|
|
self.y_axis
|
|
}
|
|
|
|
pub fn price(&self) -> u32 {
|
|
self.price
|
|
}
|
|
}
|
|
|
|
#[derive(Clone)]
|
|
pub struct SavedLayout {
|
|
id: usize,
|
|
houses: Vec<House>,
|
|
}
|
|
|
|
impl SavedLayout {
|
|
pub fn new(id: usize, houses: Vec<House>) -> Self {
|
|
SavedLayout { id, houses }
|
|
}
|
|
|
|
pub fn houses(&self) -> &Vec<House> {
|
|
&self.houses
|
|
}
|
|
|
|
pub fn id(&self) -> usize {
|
|
self.id
|
|
}
|
|
}
|
|
|
|
impl LayoutDB {
|
|
pub fn from_file(filename: &str) -> Result<Self> {
|
|
let connection = Connection::open(filename)?;
|
|
let mut layouts: HashMap<u32, Vec<(u32, u32)>> = HashMap::new();
|
|
|
|
// We need to dispose the statement so we can move the connection later
|
|
{
|
|
let mut stmt = connection.prepare("SELECT layout_id, x, y FROM houses")?;
|
|
let mut rows = stmt.query(NO_PARAMS)?;
|
|
|
|
while let Some(row) = rows.next()? {
|
|
let id: u32 = row.get(0)?;
|
|
let x: u32 = row.get(1)?;
|
|
let y: u32 = row.get(2)?;
|
|
layouts.entry(id).or_default().push((x, y));
|
|
}
|
|
}
|
|
|
|
let mut merges = HashMap::new();
|
|
{
|
|
let mut stmt = connection.prepare("SELECT left_layout_id, right_layout_id, axis, price FROM merge_lower_bounds")?;
|
|
let mut rows = stmt.query(NO_PARAMS)?;
|
|
|
|
while let Some(row) = rows.next()? {
|
|
let left_id: u32 = row.get(0)?;
|
|
let right_id: u32 = row.get(1)?;
|
|
let axis: u32 = row.get(2)?;
|
|
let price: u32 = row.get(3)?;
|
|
merges.insert((left_id as usize, right_id as usize, axis == 1), MergeLowerBound {
|
|
left_layout_id: left_id as usize,
|
|
right_layout_id: right_id as usize,
|
|
y_axis: axis == 1,
|
|
price,
|
|
});
|
|
}
|
|
}
|
|
|
|
let layouts = layouts.into_iter().map(|(id, xy_pairs)|
|
|
SavedLayout
|
|
{
|
|
id: id as usize,
|
|
houses: xy_pairs.into_iter().map(|(x, y)| House { x: x as usize, y: y as usize }).collect(),
|
|
}
|
|
).collect();
|
|
|
|
Ok(LayoutDB { connection, layouts, merge_lower_bounds: merges })
|
|
}
|
|
|
|
pub fn layouts(&self) -> &Vec<SavedLayout> {
|
|
&self.layouts
|
|
}
|
|
|
|
pub fn add_layout(&mut self, houses: &Vec<House>, fully_optimized: bool) -> Result<()> {
|
|
let transaction = self.connection.transaction()?;
|
|
transaction.execute("INSERT INTO layouts (is_fully_optimized) VALUES (?1)",
|
|
params![fully_optimized])?;
|
|
let layout_id = transaction.last_insert_rowid();
|
|
for house in houses {
|
|
transaction.execute("INSERT INTO houses (layout_id, x, y) VALUES (?1, ?2, ?3)",
|
|
params![layout_id, house.x as u32, house.y as u32])?;
|
|
}
|
|
transaction.commit()?;
|
|
self.layouts.push(SavedLayout { id: layout_id as usize, houses: houses.clone() });
|
|
Ok(())
|
|
}
|
|
|
|
pub fn get_merge_lower_bound(&self, left_layout: &SavedLayout, right_layout: &SavedLayout, y_axis: bool) -> Option<u32> {
|
|
if let Some(bound) = self.merge_lower_bounds.get(&(left_layout.id, right_layout.id, y_axis)) {
|
|
return Some(bound.price);
|
|
}
|
|
None
|
|
}
|
|
|
|
pub fn add_merge_lower_bound(&mut self, lower_bound: MergeLowerBound) -> Result<()> {
|
|
let transaction = self.connection.transaction()?;
|
|
transaction.execute("INSERT INTO merge_lower_bounds (left_layout_id, right_layout_id, axis, price) VALUES (?1, ?2, ?3, ?4) ON CONFLICT(left_layout_id, right_layout_id) DO UPDATE SET price = ?4",
|
|
params![lower_bound.left_layout_id as u32,
|
|
lower_bound.right_layout_id as u32,
|
|
if lower_bound.y_axis {1u32} else {0u32},
|
|
lower_bound.price
|
|
],
|
|
)?;
|
|
transaction.commit()?;
|
|
self.merge_lower_bounds.insert((lower_bound.left_layout_id, lower_bound.right_layout_id, lower_bound.y_axis), lower_bound);
|
|
Ok(())
|
|
}
|
|
|
|
pub fn add_merge_lower_bounds(&mut self, lower_bounds: Vec<MergeLowerBound>) -> Result<()> {
|
|
let transaction = self.connection.transaction()?;
|
|
for lower_bound in lower_bounds {
|
|
transaction.execute("INSERT INTO merge_lower_bounds (left_layout_id, right_layout_id, axis, price) VALUES (?1, ?2, ?3, ?4) ON CONFLICT(left_layout_id, right_layout_id) DO UPDATE SET price = ?4",
|
|
params![lower_bound.left_layout_id as u32,
|
|
lower_bound.right_layout_id as u32,
|
|
if lower_bound.y_axis {1u32} else {0u32},
|
|
lower_bound.price
|
|
],
|
|
)?;
|
|
self.merge_lower_bounds.insert((lower_bound.left_layout_id, lower_bound.right_layout_id, lower_bound.y_axis), lower_bound);
|
|
}
|
|
transaction.commit()?;
|
|
Ok(())
|
|
}
|
|
}
|
|
|