結果
問題 | No.1301 Strange Graph Shortest Path |
ユーザー | fukafukatani |
提出日時 | 2021-01-03 11:41:10 |
言語 | Rust (1.77.0 + proconio) |
結果 |
AC
|
実行時間 | 181 ms / 3,000 ms |
コード長 | 10,190 bytes |
コンパイル時間 | 13,299 ms |
コンパイル使用メモリ | 402,512 KB |
実行使用メモリ | 47,108 KB |
最終ジャッジ日時 | 2024-10-13 04:57:26 |
合計ジャッジ時間 | 20,334 ms |
ジャッジサーバーID (参考情報) |
judge5 / judge4 |
(要ログイン)
テストケース
テストケース表示入力 | 結果 | 実行時間 実行使用メモリ |
---|---|---|
testcase_00 | AC | 1 ms
6,820 KB |
testcase_01 | AC | 0 ms
6,816 KB |
testcase_02 | AC | 140 ms
46,100 KB |
testcase_03 | AC | 111 ms
40,832 KB |
testcase_04 | AC | 178 ms
44,908 KB |
testcase_05 | AC | 120 ms
47,108 KB |
testcase_06 | AC | 153 ms
41,096 KB |
testcase_07 | AC | 140 ms
43,756 KB |
testcase_08 | AC | 120 ms
42,592 KB |
testcase_09 | AC | 124 ms
39,040 KB |
testcase_10 | AC | 113 ms
42,260 KB |
testcase_11 | AC | 144 ms
42,692 KB |
testcase_12 | AC | 142 ms
44,012 KB |
testcase_13 | AC | 129 ms
45,440 KB |
testcase_14 | AC | 141 ms
40,632 KB |
testcase_15 | AC | 122 ms
40,404 KB |
testcase_16 | AC | 160 ms
45,516 KB |
testcase_17 | AC | 149 ms
46,580 KB |
testcase_18 | AC | 134 ms
43,260 KB |
testcase_19 | AC | 128 ms
42,528 KB |
testcase_20 | AC | 147 ms
40,448 KB |
testcase_21 | AC | 138 ms
44,624 KB |
testcase_22 | AC | 162 ms
42,128 KB |
testcase_23 | AC | 126 ms
46,648 KB |
testcase_24 | AC | 160 ms
41,088 KB |
testcase_25 | AC | 157 ms
44,812 KB |
testcase_26 | AC | 145 ms
42,988 KB |
testcase_27 | AC | 131 ms
44,020 KB |
testcase_28 | AC | 119 ms
46,044 KB |
testcase_29 | AC | 181 ms
45,108 KB |
testcase_30 | AC | 147 ms
45,480 KB |
testcase_31 | AC | 153 ms
44,168 KB |
testcase_32 | AC | 1 ms
6,820 KB |
testcase_33 | AC | 85 ms
38,220 KB |
testcase_34 | AC | 137 ms
45,908 KB |
コンパイルメッセージ
warning: unused variable: `cap` --> src/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
ソースコード
#![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::*;