結果
問題 | No.1301 Strange Graph Shortest Path |
ユーザー | fukafukatani |
提出日時 | 2021-01-03 11:41:10 |
言語 | Rust (1.77.0) |
結果 |
AC
|
実行時間 | 219 ms / 3,000 ms |
コード長 | 10,190 bytes |
コンパイル時間 | 2,090 ms |
コンパイル使用メモリ | 180,192 KB |
実行使用メモリ | 46,352 KB |
最終ジャッジ日時 | 2024-04-21 06:18:02 |
合計ジャッジ時間 | 9,627 ms |
ジャッジサーバーID (参考情報) |
judge4 / judge2 |
(要ログイン)
テストケース
テストケース表示入力 | 結果 | 実行時間 実行使用メモリ |
---|---|---|
testcase_00 | AC | 1 ms
5,248 KB |
testcase_01 | AC | 1 ms
5,376 KB |
testcase_02 | AC | 162 ms
45,768 KB |
testcase_03 | AC | 136 ms
40,832 KB |
testcase_04 | AC | 201 ms
44,672 KB |
testcase_05 | AC | 140 ms
46,080 KB |
testcase_06 | AC | 185 ms
41,100 KB |
testcase_07 | AC | 171 ms
42,932 KB |
testcase_08 | AC | 139 ms
41,352 KB |
testcase_09 | AC | 145 ms
39,040 KB |
testcase_10 | AC | 127 ms
40,752 KB |
testcase_11 | AC | 168 ms
42,368 KB |
testcase_12 | AC | 170 ms
42,496 KB |
testcase_13 | AC | 152 ms
45,696 KB |
testcase_14 | AC | 180 ms
39,040 KB |
testcase_15 | AC | 145 ms
40,532 KB |
testcase_16 | AC | 198 ms
44,416 KB |
testcase_17 | AC | 177 ms
46,352 KB |
testcase_18 | AC | 159 ms
42,112 KB |
testcase_19 | AC | 155 ms
41,396 KB |
testcase_20 | AC | 175 ms
40,448 KB |
testcase_21 | AC | 169 ms
44,464 KB |
testcase_22 | AC | 194 ms
41,728 KB |
testcase_23 | AC | 155 ms
45,696 KB |
testcase_24 | AC | 191 ms
41,216 KB |
testcase_25 | AC | 189 ms
44,544 KB |
testcase_26 | AC | 169 ms
42,496 KB |
testcase_27 | AC | 158 ms
42,600 KB |
testcase_28 | AC | 139 ms
45,312 KB |
testcase_29 | AC | 219 ms
44,032 KB |
testcase_30 | AC | 172 ms
44,160 KB |
testcase_31 | AC | 179 ms
43,776 KB |
testcase_32 | AC | 1 ms
5,376 KB |
testcase_33 | AC | 92 ms
37,900 KB |
testcase_34 | AC | 166 ms
45,952 KB |
コンパイルメッセージ
warning: unused variable: `cap` --> main.rs:30:10 | 30 | let (cap, cost) = flow.flow(0, n - 1, 2); | ^^^ help: if this is intentional, prefix it with an underscore: `_cap` | = note: `#[warn(unused_variables)]` on by default warning: 1 warning emitted
ソースコード
#![allow(unused_imports)] use std::cmp::*; use std::collections::*; use std::io::Write; use std::ops::Bound::*; #[allow(unused_macros)] macro_rules! debug { ($($e:expr),*) => { #[cfg(debug_assertions)] $({ let (e, mut err) = (stringify!($e), std::io::stderr()); writeln!(err, "{} = {:?}", e, $e).unwrap() })* }; } fn main() { let v = read_vec::<usize>(); let (n, m) = (v[0], v[1]); let mut flow = MinCostFlowGraph::new(n); for _ in 0..m { let v = read_vec::<i64>(); let (u, v, c, d) = (v[0] as usize - 1, v[1] as usize - 1, v[2], v[3]); flow.add_edge(u, v, 1, c); flow.add_edge(u, v, 1, d); flow.add_edge(v, u, 1, c); flow.add_edge(v, u, 1, d); } let (cap, cost) = flow.flow(0, n - 1, 2); println!("{}", cost); } fn read<T: std::str::FromStr>() -> T { let mut s = String::new(); std::io::stdin().read_line(&mut s).ok(); s.trim().parse().ok().unwrap() } fn read_vec<T: std::str::FromStr>() -> Vec<T> { read::<String>() .split_whitespace() .map(|e| e.parse().ok().unwrap()) .collect() } //https://github.com/rust-lang-ja/ac-library-rs pub mod internal_type_traits { use std::{ fmt, iter::{Product, Sum}, ops::{ Add, AddAssign, BitAnd, BitAndAssign, BitOr, BitOrAssign, BitXor, BitXorAssign, Div, DivAssign, Mul, MulAssign, Not, Rem, RemAssign, Shl, ShlAssign, Shr, ShrAssign, Sub, SubAssign, }, }; // Skipped: // // - `is_signed_int_t<T>` (probably won't be used directly in `modint.rs`) // - `is_unsigned_int_t<T>` (probably won't be used directly in `modint.rs`) // - `to_unsigned_t<T>` (not used in `fenwicktree.rs`) /// Corresponds to `std::is_integral` in C++. // We will remove unnecessary bounds later. // // Maybe we should rename this to `PrimitiveInteger` or something, as it probably won't be used in the // same way as the original ACL. pub trait Integral: 'static + Send + Sync + Copy + Ord + Not<Output = Self> + Add<Output = Self> + Sub<Output = Self> + Mul<Output = Self> + Div<Output = Self> + Rem<Output = Self> + AddAssign + SubAssign + MulAssign + DivAssign + RemAssign + Sum + Product + BitOr<Output = Self> + BitAnd<Output = Self> + BitXor<Output = Self> + BitOrAssign + BitAndAssign + BitXorAssign + Shl<Output = Self> + Shr<Output = Self> + ShlAssign + ShrAssign + fmt::Display + fmt::Debug + fmt::Binary + fmt::Octal + Zero + One + BoundedBelow + BoundedAbove { } /// Class that has additive identity element pub trait Zero { /// The additive identity element fn zero() -> Self; } /// Class that has multiplicative identity element pub trait One { /// The multiplicative identity element fn one() -> Self; } pub trait BoundedBelow { fn min_value() -> Self; } pub trait BoundedAbove { fn max_value() -> Self; } macro_rules! impl_integral { ($($ty:ty),*) => { $( impl Zero for $ty { #[inline] fn zero() -> Self { 0 } } impl One for $ty { #[inline] fn one() -> Self { 1 } } impl BoundedBelow for $ty { #[inline] fn min_value() -> Self { Self::min_value() } } impl BoundedAbove for $ty { #[inline] fn max_value() -> Self { Self::max_value() } } impl Integral for $ty {} )* }; } impl_integral!(i8, i16, i32, i64, i128, isize, u8, u16, u32, u64, u128, usize); } pub mod mincostflow { use crate::internal_type_traits::Integral; pub struct MinCostFlowEdge<T> { pub from: usize, pub to: usize, pub cap: T, pub flow: T, pub cost: T, } pub struct MinCostFlowGraph<T> { pos: Vec<(usize, usize)>, g: Vec<Vec<_Edge<T>>>, cost_sum: T, } impl<T> MinCostFlowGraph<T> where T: Integral + std::ops::Neg<Output = T>, { pub fn new(n: usize) -> Self { Self { pos: vec![], g: (0..n).map(|_| vec![]).collect(), cost_sum: T::zero(), } } pub fn get_edge(&self, i: usize) -> MinCostFlowEdge<T> { assert!(i < self.pos.len()); let e = &self.g[self.pos[i].0][self.pos[i].1]; let re = &self.g[e.to][e.rev]; MinCostFlowEdge { from: self.pos[i].0, to: e.to, cap: e.cap + re.cap, flow: re.cap, cost: e.cost, } } pub fn edges(&self) -> Vec<MinCostFlowEdge<T>> { let m = self.pos.len(); let mut result = vec![]; for i in 0..m { result.push(self.get_edge(i)); } result } pub fn add_edge(&mut self, from: usize, to: usize, cap: T, cost: T) -> usize { assert!(from < self.g.len()); assert!(to < self.g.len()); assert_ne!(from, to); assert!(cap >= T::zero()); assert!(cost >= T::zero()); self.pos.push((from, self.g[from].len())); self.cost_sum += cost; let rev = self.g[to].len(); self.g[from].push(_Edge { to, rev, cap, cost }); let rev = self.g[from].len() - 1; self.g[to].push(_Edge { to: from, rev, cap: T::zero(), cost: -cost, }); self.pos.len() - 1 } /// Returns (maximum flow, cost) pub fn flow(&mut self, source: usize, sink: usize, flow_limit: T) -> (T, T) { self.slope(source, sink, flow_limit).pop().unwrap() } pub fn slope(&mut self, source: usize, sink: usize, flow_limit: T) -> Vec<(T, T)> { let n = self.g.len(); assert!(source < n); assert!(sink < n); assert_ne!(source, sink); let mut dual = vec![T::zero(); n]; let mut prev_v = vec![0; n]; let mut prev_e = vec![0; n]; let mut flow = T::zero(); let mut cost = T::zero(); let mut prev_cost: Option<T> = None; let mut result = vec![(flow, cost)]; while flow < flow_limit { if !self.refine_dual(source, sink, &mut dual, &mut prev_v, &mut prev_e) { break; } let mut c = flow_limit - flow; let mut v = sink; while v != source { c = std::cmp::min(c, self.g[prev_v[v]][prev_e[v]].cap); v = prev_v[v]; } let mut v = sink; while v != source { self.g[prev_v[v]][prev_e[v]].cap -= c; let rev = self.g[prev_v[v]][prev_e[v]].rev; self.g[v][rev].cap += c; v = prev_v[v]; } let d = -dual[source]; flow += c; cost += d * c; if prev_cost == Some(d) { assert!(result.pop().is_some()); } result.push((flow, cost)); prev_cost = Some(cost); } result } fn refine_dual( &self, source: usize, sink: usize, dual: &mut [T], pv: &mut [usize], pe: &mut [usize], ) -> bool { let n = self.g.len(); let mut dist = vec![self.cost_sum; n]; let mut vis = vec![false; n]; let mut que = std::collections::BinaryHeap::new(); dist[source] = T::zero(); que.push((std::cmp::Reverse(T::zero()), source)); while let Some((_, v)) = que.pop() { if vis[v] { continue; } vis[v] = true; if v == sink { break; } for (i, e) in self.g[v].iter().enumerate() { if vis[e.to] || e.cap == T::zero() { continue; } let cost = e.cost - dual[e.to] + dual[v]; if dist[e.to] - dist[v] > cost { dist[e.to] = dist[v] + cost; pv[e.to] = v; pe[e.to] = i; que.push((std::cmp::Reverse(dist[e.to]), e.to)); } } } if !vis[sink] { return false; } for v in 0..n { if !vis[v] { continue; } dual[v] -= dist[sink] - dist[v]; } true } } struct _Edge<T> { to: usize, rev: usize, cap: T, cost: T, } #[cfg(test)] mod tests { use super::*; #[test] fn test_min_cost_flow() { let mut graph = MinCostFlowGraph::new(4); graph.add_edge(0, 1, 2, 1); graph.add_edge(0, 2, 1, 2); graph.add_edge(1, 2, 1, 1); graph.add_edge(1, 3, 1, 3); graph.add_edge(2, 3, 2, 1); let (flow, cost) = graph.flow(0, 3, 2); assert_eq!(flow, 2); assert_eq!(cost, 6); } } } use mincostflow::*;