結果
問題 | No.5007 Steiner Space Travel |
ユーザー | terry_u16 |
提出日時 | 2022-06-29 00:22:07 |
言語 | Rust (1.77.0 + proconio) |
結果 |
AC
|
実行時間 | 985 ms / 1,000 ms |
コード長 | 14,240 bytes |
コンパイル時間 | 1,842 ms |
実行使用メモリ | 2,976 KB |
スコア | 9,023,174 |
最終ジャッジ日時 | 2022-07-30 13:31:07 |
合計ジャッジ時間 | 33,333 ms |
ジャッジサーバーID (参考情報) |
judge13 / judge12 |
純コード判定しない問題か言語 |
(要ログイン)
テストケース
テストケース表示入力 | 結果 | 実行時間 実行使用メモリ |
---|---|---|
testcase_00 | AC | 985 ms
2,796 KB |
testcase_01 | AC | 985 ms
2,832 KB |
testcase_02 | AC | 985 ms
2,860 KB |
testcase_03 | AC | 985 ms
2,904 KB |
testcase_04 | AC | 985 ms
2,804 KB |
testcase_05 | AC | 985 ms
2,936 KB |
testcase_06 | AC | 983 ms
2,912 KB |
testcase_07 | AC | 984 ms
2,848 KB |
testcase_08 | AC | 985 ms
2,808 KB |
testcase_09 | AC | 985 ms
2,872 KB |
testcase_10 | AC | 985 ms
2,872 KB |
testcase_11 | AC | 984 ms
2,856 KB |
testcase_12 | AC | 985 ms
2,780 KB |
testcase_13 | AC | 985 ms
2,976 KB |
testcase_14 | AC | 985 ms
2,872 KB |
testcase_15 | AC | 984 ms
2,824 KB |
testcase_16 | AC | 983 ms
2,828 KB |
testcase_17 | AC | 984 ms
2,956 KB |
testcase_18 | AC | 985 ms
2,940 KB |
testcase_19 | AC | 985 ms
2,824 KB |
testcase_20 | AC | 984 ms
2,820 KB |
testcase_21 | AC | 985 ms
2,848 KB |
testcase_22 | AC | 985 ms
2,944 KB |
testcase_23 | AC | 985 ms
2,932 KB |
testcase_24 | AC | 985 ms
2,848 KB |
testcase_25 | AC | 985 ms
2,800 KB |
testcase_26 | AC | 985 ms
2,920 KB |
testcase_27 | AC | 984 ms
2,804 KB |
testcase_28 | AC | 985 ms
2,828 KB |
testcase_29 | AC | 985 ms
2,828 KB |
ソースコード
use std::{cmp::Reverse, collections::BinaryHeap, time::Instant}; use crate::rand::Xoshiro256; const MAP_SIZE: i32 = 1000; const MULTIPLIER: i64 = 5; macro_rules! get { ($t:ty) => { { let mut line: String = String::new(); std::io::stdin().read_line(&mut line).unwrap(); line.trim().parse::<$t>().unwrap() } }; ($($t:ty),*) => { { let mut line: String = String::new(); std::io::stdin().read_line(&mut line).unwrap(); let mut iter = line.split_whitespace(); ( $(iter.next().unwrap().parse::<$t>().unwrap(),)* ) } }; ($t:ty; $n:expr) => { (0..$n).map(|_| get!($t) ).collect::<Vec<_>>() }; ($($t:ty),*; $n:expr) => { (0..$n).map(|_| get!($($t),*) ).collect::<Vec<_>>() }; ($t:ty ;;) => { { let mut line: String = String::new(); std::io::stdin().read_line(&mut line).unwrap(); line.split_whitespace() .map(|t| t.parse::<$t>().unwrap()) .collect::<Vec<_>>() } }; ($t:ty ;; $n:expr) => { (0..$n).map(|_| get!($t ;;)).collect::<Vec<_>>() }; } #[allow(unused_macros)] macro_rules! chmin { ($base:expr, $($cmps:expr),+ $(,)*) => {{ let cmp_min = min!($($cmps),+); if $base > cmp_min { $base = cmp_min; true } else { false } }}; } #[allow(unused_macros)] macro_rules! chmax { ($base:expr, $($cmps:expr),+ $(,)*) => {{ let cmp_max = max!($($cmps),+); if $base < cmp_max { $base = cmp_max; true } else { false } }}; } #[allow(unused_macros)] macro_rules! min { ($a:expr $(,)*) => {{ $a }}; ($a:expr, $b:expr $(,)*) => {{ std::cmp::min($a, $b) }}; ($a:expr, $($rest:expr),+ $(,)*) => {{ std::cmp::min($a, min!($($rest),+)) }}; } #[allow(unused_macros)] macro_rules! max { ($a:expr $(,)*) => {{ $a }}; ($a:expr, $b:expr $(,)*) => {{ std::cmp::max($a, $b) }}; ($a:expr, $($rest:expr),+ $(,)*) => {{ std::cmp::max($a, max!($($rest),+)) }}; } #[allow(unused_macros)] macro_rules! mat { ($e:expr; $d:expr) => { vec![$e; $d] }; ($e:expr; $d:expr $(; $ds:expr)+) => { vec![mat![$e $(; $ds)*]; $d] }; } #[derive(Debug, Clone)] struct Input { n: usize, m: usize, points: Vec<Point>, distances: Vec<Vec<i64>>, since: Instant, } #[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)] struct Point { x: i32, y: i32, } impl Point { fn new(x: i32, y: i32) -> Self { Self { x, y } } fn dist_sq(&self, other: &Self) -> i64 { let dx = self.x - other.x; let dy = self.y - other.y; (dx * dx + dy * dy) as i64 } } #[derive(Debug, Clone)] struct State { points: Vec<Point>, orders: Vec<usize>, } impl State { fn init(input: &Input) -> Self { let mut points = input.points.clone(); for _ in 0..input.m { points.push(points[0]); } let mut orders = vec![]; for i in 0..input.n { orders.push(i); } orders.push(0); Self::new(points, orders) } fn new(points: Vec<Point>, orders: Vec<usize>) -> Self { Self { points, orders } } fn calc_score_all(&self, input: &Input) -> i64 { let mut score = 0; for w in self.orders.windows(2) { let (prev, next) = (w[0], w[1]); score += self.calc_score(input, prev, next); } score } #[inline] fn calc_score(&self, input: &Input, prev: usize, next: usize) -> i64 { if prev < input.n && next < input.n { input.distances[prev][next] } else { let mul0 = get_score_mul(prev, input.n); let mul1 = get_score_mul(next, input.n); let dist_sq = self.points[prev].dist_sq(&self.points[next]); dist_sq * mul0 * mul1 } } } fn main() { let input = read_input(); let state = solve(&input); write_output(&input, &state); let score = state.calc_score_all(&input); eprintln!("energy: {}", score); eprintln!( "score: {}", (1e9 / (1e3 + (score as f64).sqrt())).round() as i64 ); let elapsed = (Instant::now() - input.since).as_millis(); eprintln!("elapsed: {}ms", elapsed); } fn read_input() -> Input { let (n, m) = get!(usize, usize); let since = Instant::now(); let mut points = vec![]; for _ in 0..n { let (x, y) = get!(i32, i32); points.push(Point::new(x, y)); } let distances = warshall_floyd(&points); Input { n, m, points, distances, since, } } fn warshall_floyd(points: &[Point]) -> Vec<Vec<i64>> { let mut distances = mat![0; points.len(); points.len()]; for (i, p) in points.iter().enumerate() { for (j, q) in points.iter().enumerate() { distances[i][j] = p.dist_sq(q) * MULTIPLIER * MULTIPLIER; } } for k in 0..distances.len() { for i in 0..distances.len() { for j in 0..distances.len() { chmin!(distances[i][j], distances[i][k] + distances[k][j]); } } } distances } fn solve(input: &Input) -> State { let solution = State::init(&input); let solution = annealing(&input, solution, 0.98); let solution = restore_solution(input, &solution); solution } fn annealing(input: &Input, initial_solution: State, duration: f64) -> State { let mut solution = initial_solution; let mut best_solution = solution.clone(); let mut current_score = solution.calc_score_all(input); let initial_score = current_score; let mut best_score = current_score; let mut all_iter = 0; let mut valid_iter = 0; let mut accepted_count = 0; let mut update_count = 0; let mut rng = Xoshiro256::new(42); let duration_inv = 1.0 / duration; let since = std::time::Instant::now(); let mut time = 0.0; let temp0 = 1e5; let temp1 = 1e2; let mut inv_temp = 1.0 / temp0; while time < 1.0 { all_iter += 1; if (all_iter & ((1 << 6) - 1)) == 0 { time = (std::time::Instant::now() - since).as_secs_f64() * duration_inv; let temp = f64::powf(temp0, 1.0 - time) * f64::powf(temp1, time); inv_temp = 1.0 / temp; } // 変形 let mod_station = rng.gen_usize(0, 100) < 10; if mod_station { let station_id = input.n + rng.gen_usize(0, input.m); let mut temp_orders = solution.orders.clone(); temp_orders.retain(|&v| v != station_id); let old_p = solution.points[station_id]; let mut p = old_p; const DELTA: i32 = 100; p.x = rng.gen_i32((p.x - DELTA).max(0), (p.x + DELTA).min(MAP_SIZE) + 1); p.y = rng.gen_i32((p.y - DELTA).max(0), (p.y + DELTA).min(MAP_SIZE) + 1); solution.points[station_id] = p; let mut new_orders = Vec::with_capacity(solution.orders.len()); let mut new_score = 0; for w in temp_orders.windows(2) { let (prev, next) = (w[0], w[1]); new_orders.push(prev); let old_dist = solution.calc_score(input, prev, next); let new_dist = solution.calc_score(input, prev, station_id) + solution.calc_score(input, station_id, next); if new_dist < old_dist { new_score += new_dist; new_orders.push(station_id); } else { new_score += old_dist; } } new_orders.push(0); let score_diff = new_score - current_score; if score_diff <= 0 || rng.gen_bool(f64::exp(-score_diff as f64 * inv_temp)) { // 解の更新 current_score = new_score; accepted_count += 1; solution.orders = new_orders; if chmin!(best_score, current_score) { best_solution = solution.clone(); update_count += 1; } } else { // ロールバック solution.points[station_id] = old_p; } } else { let from = rng.gen_usize(1, solution.orders.len() - 1); let to = rng.gen_usize(from + 1, solution.orders.len()); let i0 = solution.orders[from - 1]; let i1 = solution.orders[from]; let i2 = solution.orders[to - 1]; let i3 = solution.orders[to]; let d01 = solution.calc_score(input, i0, i1); let d23 = solution.calc_score(input, i2, i3); let d02 = solution.calc_score(input, i0, i2); let d13 = solution.calc_score(input, i1, i3); // スコア計算 let score_diff = d02 + d13 - d01 - d23; let new_score = current_score + score_diff; if score_diff <= 0 || rng.gen_bool(f64::exp(-score_diff as f64 * inv_temp)) { // 解の更新 current_score = new_score; accepted_count += 1; solution.orders[from..to].reverse(); if chmin!(best_score, current_score) { best_solution = solution.clone(); update_count += 1; } } } valid_iter += 1; } eprintln!("===== annealing ====="); eprintln!("initial_score : {}", initial_score); eprintln!("score : {}", best_score); eprintln!("all iter : {}", all_iter); eprintln!("valid iter : {}", valid_iter); eprintln!("accepted : {}", accepted_count); eprintln!("updated : {}", update_count); eprintln!(""); best_solution } #[inline] fn get_score_mul(v: usize, threshold: usize) -> i64 { if v < threshold { MULTIPLIER } else { 1 } } fn restore_solution(input: &Input, solution: &State) -> State { let mut new_solution = solution.clone(); new_solution.orders.clear(); new_solution.orders.push(0); for w in solution.orders.windows(2) { let (prev, next) = (w[0], w[1]); let path = dijkstra(input, solution, prev, next); for v in path { new_solution.orders.push(v); } } new_solution } fn dijkstra(input: &Input, solution: &State, start: usize, goal: usize) -> Vec<usize> { let mut distances = vec![std::i64::MAX / 2; input.n + input.m]; let mut from = vec![!0; input.n + input.m]; distances[start] = 0; let mut queue = BinaryHeap::new(); queue.push(Reverse((0, start))); while let Some(Reverse((dist, current))) = queue.pop() { if dist > distances[current] { continue; } if current == goal { break; } let mul0 = get_score_mul(current, input.n); let p0 = solution.points[current]; for next in 0..(input.n + input.m) { let mul1 = get_score_mul(next, input.n); let p1 = solution.points[next]; let d = p0.dist_sq(&p1) * mul0 * mul1; if chmin!(distances[next], dist + d) { queue.push(Reverse((dist + d, next))); from[next] = current; } } } let mut current = goal; let mut path = vec![]; while current != start { path.push(current); current = from[current]; } path.reverse(); path } fn write_output(input: &Input, solution: &State) { for i in 0..input.m { let p = solution.points[i + input.n]; println!("{} {}", p.x, p.y); } println!("{}", solution.orders.len()); for &v in solution.orders.iter() { if v < input.n { println!("1 {}", v + 1); } else { println!("2 {}", v + 1 - input.n); } } } mod rand { pub(crate) struct Xoshiro256 { s0: u64, s1: u64, s2: u64, s3: u64, } impl Xoshiro256 { pub(crate) fn new(mut seed: u64) -> Self { let s0 = split_mix_64(&mut seed); let s1 = split_mix_64(&mut seed); let s2 = split_mix_64(&mut seed); let s3 = split_mix_64(&mut seed); Self { s0, s1, s2, s3 } } fn next(&mut self) -> u64 { let result = (self.s1 * 5).rotate_left(7) * 9; let t = self.s1 << 17; self.s2 ^= self.s0; self.s3 ^= self.s1; self.s1 ^= self.s2; self.s0 ^= self.s3; self.s2 ^= t; self.s3 = self.s3.rotate_left(45); result } pub(crate) fn gen_usize(&mut self, lower: usize, upper: usize) -> usize { assert!(lower < upper); let count = upper - lower; (self.next() % count as u64) as usize + lower } pub(crate) fn gen_i32(&mut self, lower: i32, upper: i32) -> i32 { assert!(lower < upper); let count = upper - lower; (self.next() % count as u64) as i32 + lower } pub(crate) fn gen_f64(&mut self) -> f64 { const UPPER_MASK: u64 = 0x3ff0000000000000; const LOWER_MASK: u64 = 0xfffffffffffff; let result = UPPER_MASK | (self.next() & LOWER_MASK); let result: f64 = unsafe { std::mem::transmute(result) }; result - 1.0 } pub(crate) fn gen_bool(&mut self, prob: f64) -> bool { self.gen_f64() < prob } } fn split_mix_64(x: &mut u64) -> u64 { *x += 0x9e3779b97f4a7c15; let mut z = *x; z = (z ^ z >> 30) * 0xbf58476d1ce4e5b9; z = (z ^ z >> 27) * 0x94d049bb133111eb; return z ^ z >> 31; } }