結果

問題 No.5006 Hidden Maze
ユーザー terry_u16terry_u16
提出日時 2022-06-12 18:52:47
言語 Rust
(1.77.0 + proconio)
結果
AC  
実行時間 84 ms / 2,000 ms
コード長 11,448 bytes
コンパイル時間 1,036 ms
実行使用メモリ 22,828 KB
スコア 90,965
平均クエリ数 91.35
最終ジャッジ日時 2022-06-12 18:52:55
合計ジャッジ時間 8,140 ms
ジャッジサーバーID
(参考情報)
judge16 / judge13
純コード判定しない問題か言語
このコードへのチャレンジ
(要ログイン)

テストケース

テストケース表示
入力 結果 実行時間
実行使用メモリ
testcase_00 AC 24 ms
22,636 KB
testcase_01 AC 50 ms
21,792 KB
testcase_02 AC 20 ms
22,004 KB
testcase_03 AC 21 ms
21,792 KB
testcase_04 AC 21 ms
21,964 KB
testcase_05 AC 30 ms
21,928 KB
testcase_06 AC 20 ms
22,552 KB
testcase_07 AC 19 ms
22,600 KB
testcase_08 AC 31 ms
21,928 KB
testcase_09 AC 37 ms
22,228 KB
testcase_10 AC 21 ms
21,792 KB
testcase_11 AC 20 ms
21,904 KB
testcase_12 AC 26 ms
22,288 KB
testcase_13 AC 19 ms
21,940 KB
testcase_14 AC 19 ms
21,952 KB
testcase_15 AC 21 ms
21,916 KB
testcase_16 AC 20 ms
22,144 KB
testcase_17 AC 18 ms
21,916 KB
testcase_18 AC 35 ms
22,264 KB
testcase_19 AC 20 ms
21,904 KB
testcase_20 AC 20 ms
22,216 KB
testcase_21 AC 19 ms
22,264 KB
testcase_22 AC 19 ms
21,780 KB
testcase_23 AC 19 ms
22,264 KB
testcase_24 AC 23 ms
21,892 KB
testcase_25 AC 24 ms
21,768 KB
testcase_26 AC 84 ms
21,940 KB
testcase_27 AC 22 ms
22,444 KB
testcase_28 AC 18 ms
22,240 KB
testcase_29 AC 29 ms
22,588 KB
testcase_30 AC 19 ms
22,276 KB
testcase_31 AC 25 ms
21,792 KB
testcase_32 AC 30 ms
22,444 KB
testcase_33 AC 25 ms
21,916 KB
testcase_34 AC 20 ms
22,444 KB
testcase_35 AC 21 ms
22,576 KB
testcase_36 AC 23 ms
21,844 KB
testcase_37 AC 32 ms
21,756 KB
testcase_38 AC 19 ms
21,992 KB
testcase_39 AC 17 ms
22,612 KB
testcase_40 AC 20 ms
22,456 KB
testcase_41 AC 20 ms
22,456 KB
testcase_42 AC 20 ms
21,768 KB
testcase_43 AC 23 ms
21,940 KB
testcase_44 AC 19 ms
22,384 KB
testcase_45 AC 36 ms
22,528 KB
testcase_46 AC 66 ms
21,780 KB
testcase_47 AC 22 ms
22,192 KB
testcase_48 AC 20 ms
22,240 KB
testcase_49 AC 34 ms
22,564 KB
testcase_50 AC 20 ms
22,612 KB
testcase_51 AC 19 ms
22,444 KB
testcase_52 AC 27 ms
22,264 KB
testcase_53 AC 23 ms
21,768 KB
testcase_54 AC 20 ms
22,456 KB
testcase_55 AC 19 ms
22,588 KB
testcase_56 AC 21 ms
21,940 KB
testcase_57 AC 25 ms
22,216 KB
testcase_58 AC 21 ms
22,620 KB
testcase_59 AC 23 ms
22,828 KB
testcase_60 AC 20 ms
21,916 KB
testcase_61 AC 18 ms
21,952 KB
testcase_62 AC 20 ms
22,600 KB
testcase_63 AC 20 ms
21,792 KB
testcase_64 AC 22 ms
21,892 KB
testcase_65 AC 19 ms
21,792 KB
testcase_66 AC 20 ms
21,892 KB
testcase_67 AC 23 ms
21,940 KB
testcase_68 AC 31 ms
21,952 KB
testcase_69 AC 26 ms
21,808 KB
testcase_70 AC 18 ms
22,564 KB
testcase_71 AC 18 ms
22,216 KB
testcase_72 AC 20 ms
22,600 KB
testcase_73 AC 21 ms
21,892 KB
testcase_74 AC 20 ms
21,780 KB
testcase_75 AC 19 ms
22,576 KB
testcase_76 AC 20 ms
21,804 KB
testcase_77 AC 31 ms
21,892 KB
testcase_78 AC 30 ms
21,928 KB
testcase_79 AC 55 ms
22,228 KB
testcase_80 AC 20 ms
21,952 KB
testcase_81 AC 20 ms
21,904 KB
testcase_82 AC 21 ms
21,884 KB
testcase_83 AC 20 ms
22,444 KB
testcase_84 AC 27 ms
21,904 KB
testcase_85 AC 22 ms
22,576 KB
testcase_86 AC 18 ms
22,588 KB
testcase_87 AC 27 ms
21,952 KB
testcase_88 AC 23 ms
22,276 KB
testcase_89 AC 46 ms
21,928 KB
testcase_90 AC 23 ms
22,564 KB
testcase_91 AC 19 ms
22,444 KB
testcase_92 AC 20 ms
22,576 KB
testcase_93 AC 19 ms
22,620 KB
testcase_94 AC 23 ms
22,228 KB
testcase_95 AC 20 ms
22,228 KB
testcase_96 AC 19 ms
21,952 KB
testcase_97 AC 23 ms
21,992 KB
testcase_98 AC 25 ms
21,916 KB
testcase_99 AC 22 ms
21,940 KB
権限があれば一括ダウンロードができます

ソースコード

diff #

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 * (1.0 - p),
            EdgeState::NoWall => 1.0 - p,
            EdgeState::MayBeWall(c) => p.powi(*c) * (1.0 - p),
        }
    }
}

// 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, &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, rng: &mut Xorshift) -> 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) - 1e-3 * (c.row as f64 - c.col as f64).abs())
                    .max(0.0);
                let mul = rng.randf() * 0.1 + 0.9;
                let next_p = p * prob * mul;

                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 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.0
    pub 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
    }
}
0