#![allow(non_snake_case, unused)] use std::io::*; use std::{collections::*, fmt::format}; use std::{cmp::*, vec}; use crate::input::{*, marker::*}; // コピペで使える proconio もどき // cunitacさんからお借りしています // https://gist.github.com/cunitac/b00be62bf68c9fb6055d22eb77c17e14 pub mod input { use std::{ cell::RefCell, fmt::Debug, io::{stdin, BufRead, BufReader, Stdin}, str::{FromStr, SplitWhitespace}, }; thread_local!( pub static STDIN_SOURCE: RefCell = RefCell::new(Source { stdin: BufReader::new(stdin()), tokens: "".split_whitespace(), }); ); pub struct Source { stdin: BufReader, tokens: SplitWhitespace<'static>, } impl Source { pub fn next_token(&mut self) -> Option<&str> { self.tokens.next().or_else(|| { let mut input = String::new(); self.stdin.read_line(&mut input).unwrap(); self.tokens = Box::leak(input.into_boxed_str()).split_whitespace(); self.tokens.next() }) } } #[macro_export] macro_rules! read_value { (from $s:expr, [$t:tt; $n:expr]) => { (0..$n).map(|_| $crate::read_value!(from $s, $t)).collect::>() }; (from $s:expr, [$t:tt]) => { let n = $crate::read_value!(from $s, usize); $crate::read_value!(from $s, [$t; n]) }; (from $s:expr, $t:ty) => { <$t as $crate::input::Readable>::read(&mut $s) }; (from $s:expr, $($t:tt),* $(,)?) => { ($($crate::read_value!(from $s, $t)),*) }; ($($r:tt)*) => { $crate::input::STDIN_SOURCE.with(|s| { let mut s = s.borrow_mut(); $crate::read_value!(from s, $($r)*) }) } } #[macro_export] macro_rules! input { () => { }; ($x:tt: $t:tt, $($r:tt)*) => { let $x = $crate::read_value!($t); $crate::input!($($r)*); }; (mut $x:tt: $t:tt, $($r:tt)*) => { let mut $x = $crate::read_value!($t); $crate::input!($($r)*); }; (from $s:expr, $x:tt, $t:tt, $($r:tt)*) => { let $x = $crate::read_value!(from $s, $t); $crate::input!(from $s, $($r)*); }; (from $s:expr, mut $x:tt, $t:tt, $($r:tt)*) => { let mut $x = $crate::read_value!(from $s, $t); $crate::input!(from $s, $($r)*); }; ($($r:tt)*) => { $crate::input!($($r)*,); }; } pub trait Readable { type Output; fn read(source: &mut Source) -> Self::Output; } impl, E: Debug> Readable for T { type Output = T; fn read(source: &mut Source) -> T { source.next_token().unwrap().parse().unwrap() } } pub mod marker { macro_rules! impl_readable { ($e:ident, $t:ty, $u:ty, $f:expr) => { pub enum $e {} impl $crate::input::Readable for $e { type Output = $t; fn read(mut source: &mut $crate::input::Source) -> $t { $f($crate::read_value!(from source, $u)) } } }; } impl_readable!(Usize1, usize, usize, |x| x - 1); impl_readable!(Isize1, isize, isize, |x| x - 1); impl_readable!(Chars, Vec, String, |x: String| x.chars().collect()); impl_readable!(Bytes, Vec, String, |x: String| x.bytes().collect()); } } const N: usize = 100; const M: usize = 8; const ALPHA: i64 = 5; const INF: i64 = 1_000_000_000; const TL: f64 = 0.97; pub fn get_time() -> f64 { static mut STIME: f64 = -1.0; let t = std::time::SystemTime::now().duration_since(std::time::UNIX_EPOCH).unwrap(); let ms = t.as_secs() as f64 + t.subsec_nanos() as f64 * 1e-9; unsafe { if STIME < 0.0 { STIME = ms; } // ローカル環境とジャッジ環境の実行速度差はget_timeで吸収しておくと便利 #[cfg(feature = "local")] { (ms - STIME) * 1.5 } #[cfg(not(feature = "local"))] { (ms - STIME) } } } // 距離の二乗を返す pub fn squared_distance(x1: i64, y1: i64, x2: i64, y2: i64) -> i64 { (x1 - x2) * (x1 - x2) + (y1 - y2) * (y1 - y2) } #[derive(Clone)] pub struct Input { pos: Vec<(i64, i64)>, } impl Input { fn new() -> Self { input! { _n: usize, _m: usize, } let mut pos = vec![]; for _ in 0..N { input! { ai: i64, bi: i64, } pos.push((ai, bi)); } Self { pos } } } // 初期解を貪欲法で作る pub fn init_route_greedy(input: &Input) -> Vec<(usize, usize)> { let mut route = vec![(1, 0)]; let mut visited = vec![false; N]; visited[0] = true; while route.len() < N { let &(crt_t, crt_r) = route.last().unwrap(); let mut min_dist = INF; let mut min_index = !0; for i in 1..N { if crt_r == i || visited[i] {continue;} let (crt_x, crt_y) = input.pos[crt_r]; let (next_x, next_y) = input.pos[i]; let dist = squared_distance(crt_x, crt_y, next_x, next_y); if dist < min_dist { min_dist = dist; min_index = i; } } route.push((1, min_index)); visited[min_index] = true; } route.push((1, 0)); route } #[derive(Clone)] struct State { turn: i64, is_done: bool, game_score: i64, evaluated_score: i64, station: Vec<(i64, i64)>, // i番目のステーションの場所 route: Vec<(usize, usize)>, // 道順 (惑星orステーション,番号) } impl State { fn new(input: &Input) -> Self { let mut station = vec![ (300, 300), (300, 600), (300, 900), (600, 300), (600, 900), (900, 300), (900, 600), (900, 900) ]; let mut route = init_route_greedy(&input); Self { turn: 0, is_done: false, game_score: 0, evaluated_score: 0, station, route, } } // 2-optを行う pub fn two_opt(&mut self) { let v = self.route.len(); } // 回答を出力 pub fn print(&self) { for i in 0..M { let (ci, di) = self.station[i]; println!("{} {}", ci, di); } let v = self.route.len(); println!("{}", v); for i in 0..v { let (ti, ri) = self.route[i]; println!("{} {}", ti, ri + 1); } } } fn main() { // 2-optに見えるが,再訪ありなので単純には適応できない // ただ,宇宙ステーションに再訪してもいいが,惑星は再訪しないほうがよい // 近傍: // - 2-opt (ただし,最初と最後が惑星1なのは固定する) // - 少なくとも一方が宇宙ステーションであるパスの追加 // - いずれかの宇宙ステーションの座標をずらす (あるいは,これはあらかじめk-meansで求めておく) get_time(); let input = Input::new(); let mut state = State::new(&input); state.print(); eprintln!("score: {}", state.game_score); eprintln!("time: {}", get_time()); }