// #![allow(unused_imports)] // #![allow(dead_code)] // #![allow(non_snake_case)] use std::env; use std::io::{self, BufRead, BufReader, Read, Stdin}; use std::mem; use std::str::FromStr; use std::string::String; use std::time; const TIMELIMIT: u64 = 950; const INF: usize = 1 << 28; const N: usize = 47; const R: usize = 1000; const M: usize = 400; const K: usize = 25; #[derive(Debug)] pub struct Scanner { reader: BufReader, } fn scanner() -> Scanner { Scanner::new(io::stdin()) } impl Scanner { pub fn new(read: R) -> Scanner { Scanner { reader: BufReader::new(read) } } pub fn next_str(&mut self) -> Option { let mut buf = [0; 1]; let size = self.reader.read(&mut buf).unwrap(); if size == 0 { None } else { self.skip_whitespace(&mut buf)?; let mut v = vec![buf[0]]; loop { let size = self.reader.read(&mut buf).unwrap(); if size == 0 || buf[0].is_ascii_whitespace() { break; } v.push(buf[0]); } Some(String::from_utf8(v).unwrap()) } } pub fn next_line(&mut self) -> String { let mut line = String::new(); self.reader.read_line(&mut line).unwrap(); if let Some(s) = line.strip_suffix("\n") { s.to_string() } else { line } } pub fn next_as(&mut self) -> Option { let s = self.next_str()?; S::from_str(&s).ok() } pub fn str(&mut self) -> String { self.next_str().unwrap() } pub fn i32(&mut self) -> i32 { self.next_as::().unwrap() } pub fn u32(&mut self) -> u32 { self.next_as::().unwrap() } pub fn u64(&mut self) -> u64 { self.next_as::().unwrap() } pub fn usize(&mut self) -> usize { self.next_as::().unwrap() } fn skip_whitespace(&mut self, mut buf: &mut [u8]) -> Option { loop { if !buf[0].is_ascii_whitespace() { return Some(buf[0]); } let size = self.reader.read(&mut buf).unwrap(); if size == 0 { return None; } } } } struct XorShift32 { state: u32, } impl XorShift32 { fn from_seed(seed: u32) -> Self { let initial_state = if seed == 0 { 1 } else { seed }; XorShift32 { state: initial_state } } fn next_u32(&mut self) -> u32 { let mut x = self.state; x ^= x << 13; x ^= x >> 17; x ^= x << 5; self.state = x; x } fn next_f64(&mut self) -> f64 { self.next_u32() as f64 / (u32::MAX as f64 + 1.0) } } #[derive(Debug)] struct Timer { start_time: time::Instant, limit: time::Instant, } impl Timer { fn new(tl: u64) -> Timer { let start_time = time::Instant::now(); Timer { start_time, limit: start_time + time::Duration::from_millis(tl) } } fn elapsed(&self) -> u64 { self.start_time.elapsed().as_millis() as u64 } fn tl(&self) -> u64 { (self.limit - self.start_time).as_millis() as u64 } } fn time_to_str(t: usize) -> String { let h = t / 12 + 6; let m = (t % 12) * 5; format!("{:02}:{:02}", h, m) } struct Input { ws: [u64; N], start_at: Vec>>, dist: Vec<[usize; N]>, far: Vec<[bool; N]>, } impl Input { fn new() -> Input { let mut sc = scanner(); sc.next_line(); let mut pos = [Pos::new(0, 0); N]; let mut ws = [0; N]; for i in 0..N { let y = sc.i32() as usize; let x = sc.i32() as usize; let w = sc.u64(); pos[i] = Pos::new(y, x); ws[i] = w; } let mut dist = vec![[0; N]; N]; let mut far = vec![[false; N]; N]; for i in 0..N { for j in 0..N { let d2 = pos[i].dist2(&pos[j]); if d2 >= (R / 4) * (R / 4) { far[i][j] = true; } dist[i][j] = (((d2 as f64).sqrt() * 60.0 / 800.0 + 40.0) / 5.0).ceil() as usize; } dist[i][i] = INF; } sc.usize(); let mut flight = vec![vec![]; N]; for _ in 0..M { let a = sc.usize() - 1; let ss = sc.str(); let b = sc.usize() - 1; let ts = sc.str(); let s = ((ss[0..2].parse::().unwrap() - 6) * 60 + ss[3..5].parse::().unwrap()) / 5; let t = ((ts[0..2].parse::().unwrap() - 6) * 60 + ts[3..5].parse::().unwrap()) / 5; flight[b].push((a, s, t)); assert!(t - s == dist[a][b]); } let mut start_at = vec![vec![vec![INF; N]; N]; 21]; for i in 0..N { let mut time = [INF; N]; for st in 0..=20 { time[i] = st * 6 + 60; let mut heap = std::collections::BinaryHeap::new(); heap.push((time[i], i)); while let Some((now, u)) = heap.pop() { if time[u] < now { continue; } for &(v, s, t) in &flight[u] { if t <= now && (time[v] == INF || s > time[v]) { time[v] = s; heap.push((s, v)); } } } for j in 0..N { start_at[st][j][i] = time[j]; // eprintln!( // "{:?}->{:?} {} {}", // j, // i, // time_to_str(st * 6 + 60), // if time[j] == INF { "-".to_string() } else { time_to_str(time[j]) } // ); } } } Input { ws, start_at, dist, far } } } #[derive(Debug, Clone, Copy)] struct Pos { y: usize, x: usize, } impl Pos { fn new(y: usize, x: usize) -> Pos { Pos { y, x } } fn dist2(&self, other: &Pos) -> usize { let dy = self.y as i32 - other.y as i32; let dx = self.x as i32 - other.x as i32; (dy * dy + dx * dx) as usize } } #[derive(Debug, Clone, Copy)] struct Flight { a: usize, b: usize, s: usize, t: usize, } impl Flight { fn new(a: usize, b: usize, s: usize, t: usize) -> Flight { Flight { a, b, s, t } } } #[derive(Debug, Clone)] struct Result { flights: Vec>, score: f64, } impl Result { fn new(flights: Vec>, score: f64) -> Result { Result { flights, score } } fn new_empty() -> Result { Result { flights: vec![vec![]; K], score: 0.0 } } fn output(&self) { for i in 0..K { println!("{}", self.flights[i].len()); for f in &self.flights[i] { println!("{} {} {} {}", f.a + 1, time_to_str(f.s), f.b + 1, time_to_str(f.t)); } } } } struct Solver { input: Input, timer: Timer, rng: XorShift32, start_at: Vec>>, } impl Solver { fn new(input: Input) -> Solver { let tl = env::var("TL").map_or(TIMELIMIT, |v| v.parse().unwrap()); let timer = Timer::new(tl); let rng = XorShift32::from_seed(2); let start_at = vec![vec![vec![INF; N]; N]; 21]; Solver { input, timer, rng, start_at } } fn calc_score(&mut self, flights: &[Vec]) -> (f64, Vec>>) { let mut direct = vec![vec![]; N]; for fs in flights { for f in fs { direct[f.b].push((f.a, f.s, f.t)); } } for i in 0..self.start_at.len() { for j in 0..N { self.start_at[i][j].fill(INF); } } let mut start_at = vec![vec![vec![INF; N]; N]; 21]; for i in 0..N { let mut time = [INF; N]; for st in 0..=20 { time[i] = st * 6 + 60; let mut heap = std::collections::BinaryHeap::new(); heap.push((time[i], i)); while let Some((now, u)) = heap.pop() { if time[u] < now { continue; } for &(v, s, t) in &direct[u] { if t <= now && (time[v] == INF || s > time[v]) { time[v] = s; heap.push((s, v)); } } } for j in 0..N { start_at[st][j][i] = time[j]; // eprintln!( // "{:?}->{:?} {} {}", // j, // i, // time_to_str(st * 6 + 60), // if time[j] == INF { "-".to_string() } else { time_to_str(time[j]) } // ); } } } let mut v_sq = 0; let mut v_ci = 0; for i in 0..N { for j in 0..N { if !self.input.far[i][j] { continue; } for k in 0..=20 { let v0 = self.input.start_at[k][i][j]; let v1 = start_at[k][i][j]; if v1 != INF && (v0 == INF || v0 < v1) { // eprintln!( // "ci: {:?} {:?} {:?} {:?} {:?} {:?}", // i, // j, // k, // v0, // v1, // self.input.ws[i] * self.input.ws[j] / 10_000_000_000 // ); v_ci += self.input.ws[i] * self.input.ws[j]; } else { v_sq += self.input.ws[i] * self.input.ws[j]; } } } } // eprintln!("v_sq:{:?} v_ci:{:?}", v_sq / 10_000_000_000, v_ci / 10_000_000_000); (v_ci as f64 / (v_ci + v_sq) as f64, start_at) } fn random_flight(&mut self) -> Vec { let mut flights = vec![]; let max_v = self.rng.next_u32() as usize % (N / 2 - N / 10 + 1) + N / 10; let mut now = self.rng.next_u32() as usize % 1; let mut pos = self.rng.next_u32() as usize % max_v; let mut fail = 0; loop { if now < 170 { let mut found = false; for i in 0..N / 10 { let d = self.input.dist[pos][i]; if now + d > 180 { continue; } let nt = if now + d < 60 { 0 } else { (now + d - 60) / 6 }; if self.start_at[nt][pos][i] == INF { flights.push(Flight::new(pos, i, now, now + d)); now += d; pos = i; found = true; } } if found { continue; } } let mv = if fail > 10 { N - 1 } else { max_v - 1 }; let mut next = self.rng.next_u32() as usize % mv; if next >= pos { next += 1; } let wait = self.rng.next_u32() as usize % 2; let d = self.input.dist[pos][next]; if now + d + wait > 180 { fail += 1; if fail == 100 { break; } continue; } flights.push(Flight::new(pos, next, now + wait, now + wait + d)); now += wait + d; pos = next; } flights } fn solve(&mut self, tl: u64) -> Result { let mut flights = vec![]; for _ in 0..K { flights.push(self.random_flight()); } let (mut cur_score, start_at) = self.calc_score(&flights); self.start_at = start_at; let mut best_score = cur_score; let mut best_flights = flights.clone(); let initial_cooler: f64 = env::var("IC").map_or(100.0, |v| v.parse().unwrap()); let final_cooler: f64 = env::var("FC").map_or(1000.0, |v| v.parse().unwrap()); let mut cooler = initial_cooler; let begin_time = self.timer.elapsed(); let mut turn = 0; loop { if turn & 0xF == 0 { let elapsed = self.timer.elapsed(); if elapsed > tl { eprintln!("total_turn: {}", turn); break; } let ratio = (elapsed - begin_time) as f64 / (TIMELIMIT - begin_time) as f64; cooler = (initial_cooler.ln() * (1.0 - ratio) + final_cooler.ln() * ratio).exp(); } turn += 1; let ch_fi = self.rng.next_u32() as usize % K; let new_flights = self.random_flight(); let old_flights = mem::replace(&mut flights[ch_fi], new_flights); let (new_score, new_start_at) = self.calc_score(&flights); if self.accept(new_score - cur_score, cooler) { cur_score = new_score; self.start_at = new_start_at; if cur_score > best_score { eprintln!("best_score:{:?} at turn:{:?}", cur_score, turn); best_score = cur_score; best_flights = flights.clone(); } } else { flights[ch_fi] = old_flights; } } Result::new(best_flights, best_score) } fn accept(&mut self, diff: f64, cooler: f64) -> bool { if diff >= 0.0 { return true; } let v = diff as f64 * cooler; if v < -6.0 { return false; } return self.rng.next_f64() < v.exp(); } } fn main() { let input = Input::new(); let mut solver = Solver::new(input); let mut best_res = Result::new_empty(); let part = env::var("PART").map_or(1, |v| v.parse().unwrap()); for i in 0..part { let result = solver.solve(solver.timer.tl() * (i + 1) / part); if result.score > best_res.score { best_res = result; } } best_res.output(); eprintln!("final_score:{:?}", (best_res.score * 1e6) as i64); }