結果
問題 | No.5006 Hidden Maze |
ユーザー |
![]() |
提出日時 | 2022-06-12 17:46:49 |
言語 | Rust (1.83.0 + proconio) |
結果 |
AC
|
実行時間 | 80 ms / 2,000 ms |
コード長 | 12,327 bytes |
コンパイル時間 | 2,593 ms |
実行使用メモリ | 22,644 KB |
スコア | 83,107 |
平均クエリ数 | 169.93 |
最終ジャッジ日時 | 2022-06-12 17:47:00 |
合計ジャッジ時間 | 8,825 ms |
ジャッジサーバーID (参考情報) |
judge15 / judge14 |
純コード判定しない問題か言語 |
(要ログイン)
ファイルパターン | 結果 |
---|---|
other | AC * 100 |
ソースコード
use std::collections::BinaryHeap;use grid::{Coordinate, Map2d, ADJACENTS, DIRECTIONS};#[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),+))}};}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<_>>()};}const MAP_SIZE: usize = 20;const DEFAULT_PROB: f64 = 1.0 - 0.2;#[derive(Debug, Clone, Copy)]struct Input {p: f64,}#[derive(Debug, Clone)]struct State {map: Map2d<[Edge; 4]>,}#[derive(Debug, Clone, Copy)]struct Edge {next: Option<Coordinate>,state: EdgeState,}impl Edge {fn new(next: Option<Coordinate>, state: EdgeState) -> Self {Self { next, state }}}#[derive(Debug, Clone, Copy, PartialEq, Eq)]enum EdgeState {NotEnter,NoWall,MayBeWall(i32),}impl EdgeState {#[inline]fn prob(&self, p: f64) -> f64 {match self {EdgeState::NotEnter => DEFAULT_PROB,EdgeState::NoWall => 1.0 - p,EdgeState::MayBeWall(c) => p.powi(*c),}}}// Partial orderなものをTotal orderにする#[derive(PartialEq, PartialOrd)]pub struct Total<T>(pub T);impl<T: PartialEq> Eq for Total<T> {}impl<T: PartialOrd> Ord for Total<T> {fn cmp(&self, other: &Total<T>) -> std::cmp::Ordering {self.0.partial_cmp(&other.0).unwrap()}}fn main() {let (input, state) = read_input();let score = solve(&input, state);eprintln!("score: {}", score);}fn read_input() -> (Input, State) {let (_, _, p) = get!(usize, usize, i64);let p = p as f64 * 0.01;let mut map = Map2d::new(vec![[Edge::new(None, EdgeState::NotEnter); 4]; MAP_SIZE * MAP_SIZE],MAP_SIZE,);for row in 0..MAP_SIZE {for col in 0..MAP_SIZE {let c = Coordinate::new(row, col);for (dir, adj) in ADJACENTS.iter().enumerate() {let next = c + *adj;if next.in_map(MAP_SIZE) {map[c][dir].next = Some(next);}}}}let input = Input { p };let state = State { map };(input, state)}fn solve(input: &Input, mut state: State) -> i64 {let mut rng = Xorshift::new();for trial in 0.. {let moves = dijkstra(input, &state);let moves = mod_moves(moves, &state, &mut rng);if let Some(stop) = write_output(&moves) {update_state(&mut state, &moves[..stop], moves[stop])} else {return 1001 - trial - 1;}}0}fn dijkstra(input: &Input, state: &State) -> Vec<usize> {let mut distances = Map2d::new(vec![0.0; MAP_SIZE * MAP_SIZE], MAP_SIZE);let mut from = Map2d::new(vec![0; MAP_SIZE * MAP_SIZE], MAP_SIZE);let mut queue = BinaryHeap::new();distances[Coordinate::new(0, 0)] = 1.0;queue.push((Total(1.0), Coordinate::new(0, 0)));let goal = Coordinate::new(MAP_SIZE - 1, MAP_SIZE - 1);while let Some((Total(p), c)) = queue.pop() {if distances[c] < p {continue;}if c == goal {break;}for dir in 0..4 {let edge = state.map[c][dir];if let Some(next) = edge.next {let prob = (edge.state.prob(input.p) - 5e-3 * (c.row as f64 - c.col as f64).abs()).max(0.0);let next_p = p * prob;if chmax!(distances[next], next_p) {from[next] = dir;queue.push((Total(next_p), next));}}}}let mut current = goal;let mut moves = vec![];while current != Coordinate::new(0, 0) {let dir = from[current];moves.push(dir);current = current + ADJACENTS[dir ^ 2];}moves.reverse();moves}fn update_state(state: &mut State, ok: &[usize], ng: usize) {let mut current = Coordinate::new(0, 0);for &ok in ok {state.map[current][ok].state = EdgeState::NoWall;current = current + ADJACENTS[ok];}state.map[current][ng].state = match state.map[current][ng].state {EdgeState::NotEnter => EdgeState::MayBeWall(1),EdgeState::NoWall => EdgeState::NoWall,EdgeState::MayBeWall(c) => EdgeState::MayBeWall(c + 1),}}fn mod_moves(mut moves: Vec<usize>, state: &State, rng: &mut Xorshift) -> Vec<usize> {let mut last_seen = 0;let mut current = Coordinate::new(0, 0);for (i, m) in moves.iter().enumerate() {let adj = ADJACENTS[*m];let s = state.map[current][*m].state;if s != EdgeState::NotEnter {last_seen = i;}current = current + adj;}loop {for i in (last_seen + 1)..moves.len() {let j = rng.rand((moves.len() - i) as u64) as usize + i;moves.swap(i, j);}let mut current = Coordinate::new(0, 0);let mut ok = true;for m in moves.iter() {let next = current + ADJACENTS[*m];if !next.in_map(MAP_SIZE) {ok = false;break;}current = next;}if ok {break;}}moves}fn write_output(moves: &[usize]) -> Option<usize> {let output = moves.iter().map(|dir| DIRECTIONS[*dir]).collect::<String>();println!("{}", output);let judge = get!(i64);if judge == -1 {None} else {Some(judge as usize)}}#[allow(dead_code)]mod grid {#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)]pub struct Coordinate {pub row: usize,pub col: usize,}impl Coordinate {pub const fn new(row: usize, col: usize) -> Self {Self { row, col }}pub fn in_map(&self, size: usize) -> bool {self.row < size && self.col < size}pub const fn to_index(&self, size: usize) -> usize {self.row * size + self.col}pub const fn dist(&self, other: &Self) -> usize {Self::dist_1d(self.row, other.row) + Self::dist_1d(self.col, other.col)}const fn dist_1d(x0: usize, x1: usize) -> usize {(x0 as i64 - x1 as i64).abs() as usize}}#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)]pub struct CoordinateDiff {pub dr: usize,pub dc: usize,}impl CoordinateDiff {pub const fn new(dr: usize, dc: usize) -> Self {Self { dr, dc }}pub const fn invert(&self) -> Self {Self::new(0usize.wrapping_sub(self.dr), 0usize.wrapping_sub(self.dc))}}impl std::ops::Add<CoordinateDiff> for Coordinate {type Output = Coordinate;fn add(self, rhs: CoordinateDiff) -> Self::Output {Coordinate::new(self.row.wrapping_add(rhs.dr), self.col.wrapping_add(rhs.dc))}}pub const ADJACENTS: [CoordinateDiff; 4] = [CoordinateDiff::new(!0, 0),CoordinateDiff::new(0, 1),CoordinateDiff::new(1, 0),CoordinateDiff::new(0, !0),];pub const DIRECTIONS: [char; 4] = ['U', 'R', 'D', 'L'];#[derive(Debug, Clone)]pub struct Map2d<T> {pub width: usize,pub height: usize,map: Vec<T>,}impl<T> Map2d<T> {pub fn new(map: Vec<T>, width: usize) -> Self {let height = map.len() / width;debug_assert!(width * height == map.len());Self { width, height, map }}}impl<T> std::ops::Index<Coordinate> for Map2d<T> {type Output = T;#[inline]fn index(&self, coordinate: Coordinate) -> &Self::Output {&self.map[coordinate.row * self.width + coordinate.col]}}impl<T> std::ops::IndexMut<Coordinate> for Map2d<T> {#[inline]fn index_mut(&mut self, coordinate: Coordinate) -> &mut Self::Output {&mut self.map[coordinate.row * self.width + coordinate.col]}}impl<T> std::ops::Index<&Coordinate> for Map2d<T> {type Output = T;#[inline]fn index(&self, coordinate: &Coordinate) -> &Self::Output {&self.map[coordinate.row * self.width + coordinate.col]}}impl<T> std::ops::IndexMut<&Coordinate> for Map2d<T> {#[inline]fn index_mut(&mut self, coordinate: &Coordinate) -> &mut Self::Output {&mut self.map[coordinate.row * self.width + coordinate.col]}}impl<T> std::ops::Index<usize> for Map2d<T> {type Output = [T];#[inline]fn index(&self, row: usize) -> &Self::Output {let begin = row * self.width;let end = begin + self.width;&self.map[begin..end]}}impl<T> std::ops::IndexMut<usize> for Map2d<T> {#[inline]fn index_mut(&mut self, row: usize) -> &mut Self::Output {let begin = row * self.width;let end = begin + self.width;&mut self.map[begin..end]}}}#[derive(Debug)]#[allow(dead_code)]pub struct Xorshift {seed: u64,}impl Xorshift {#[allow(dead_code)]pub fn new() -> Xorshift {Xorshift {seed: 0xf0fb588ca2196dac,}}#[allow(dead_code)]pub fn with_seed(seed: u64) -> Xorshift {Xorshift { seed: seed }}#[inline]#[allow(dead_code)]pub fn next(&mut self) -> u64 {self.seed = self.seed ^ (self.seed << 13);self.seed = self.seed ^ (self.seed >> 7);self.seed = self.seed ^ (self.seed << 17);self.seed}#[inline]#[allow(dead_code)]pub fn rand(&mut self, m: u64) -> u64 {self.next() % m}#[inline]#[allow(dead_code)]// 0.0 ~ 1.0pub fn randf(&mut self) -> f64 {use std::mem;const UPPER_MASK: u64 = 0x3FF0000000000000;const LOWER_MASK: u64 = 0xFFFFFFFFFFFFF;let tmp = UPPER_MASK | (self.next() & LOWER_MASK);let result: f64 = unsafe { mem::transmute(tmp) };result - 1.0}}