結果

問題 No.5006 Hidden Maze
ユーザー terry_u16terry_u16
提出日時 2022-06-12 17:26:41
言語 Rust
(1.77.0 + proconio)
結果
AC  
実行時間 505 ms / 2,000 ms
コード長 14,922 bytes
コンパイル時間 1,390 ms
実行使用メモリ 22,856 KB
スコア 71,991
平均クエリ数 281.09
最終ジャッジ日時 2022-06-12 17:27:34
合計ジャッジ時間 50,879 ms
ジャッジサーバーID
(参考情報)
judge13 / judge12
純コード判定しない問題か言語
このコードへのチャレンジ
(要ログイン)

テストケース

テストケース表示
入力 結果 実行時間
実行使用メモリ
testcase_00 AC 427 ms
22,228 KB
testcase_01 AC 474 ms
22,004 KB
testcase_02 AC 423 ms
21,756 KB
testcase_03 AC 425 ms
22,716 KB
testcase_04 AC 446 ms
22,004 KB
testcase_05 AC 428 ms
21,756 KB
testcase_06 AC 458 ms
21,992 KB
testcase_07 AC 448 ms
21,780 KB
testcase_08 AC 476 ms
21,768 KB
testcase_09 AC 462 ms
22,216 KB
testcase_10 AC 412 ms
21,992 KB
testcase_11 AC 439 ms
21,940 KB
testcase_12 AC 431 ms
21,904 KB
testcase_13 AC 441 ms
21,892 KB
testcase_14 AC 452 ms
21,892 KB
testcase_15 AC 413 ms
22,600 KB
testcase_16 AC 427 ms
22,216 KB
testcase_17 AC 426 ms
21,792 KB
testcase_18 AC 468 ms
21,940 KB
testcase_19 AC 479 ms
21,952 KB
testcase_20 AC 414 ms
21,892 KB
testcase_21 AC 433 ms
21,928 KB
testcase_22 AC 420 ms
21,904 KB
testcase_23 AC 415 ms
22,572 KB
testcase_24 AC 443 ms
22,456 KB
testcase_25 AC 442 ms
21,780 KB
testcase_26 AC 495 ms
22,216 KB
testcase_27 AC 492 ms
21,952 KB
testcase_28 AC 499 ms
21,780 KB
testcase_29 AC 485 ms
21,904 KB
testcase_30 AC 426 ms
21,940 KB
testcase_31 AC 425 ms
21,892 KB
testcase_32 AC 440 ms
22,004 KB
testcase_33 AC 426 ms
22,444 KB
testcase_34 AC 443 ms
22,004 KB
testcase_35 AC 416 ms
21,928 KB
testcase_36 AC 420 ms
21,892 KB
testcase_37 AC 505 ms
22,588 KB
testcase_38 AC 459 ms
22,228 KB
testcase_39 AC 412 ms
21,952 KB
testcase_40 AC 423 ms
22,844 KB
testcase_41 AC 445 ms
21,756 KB
testcase_42 AC 420 ms
22,288 KB
testcase_43 AC 433 ms
21,928 KB
testcase_44 AC 434 ms
21,780 KB
testcase_45 AC 437 ms
21,952 KB
testcase_46 AC 492 ms
22,856 KB
testcase_47 AC 452 ms
21,952 KB
testcase_48 AC 494 ms
22,444 KB
testcase_49 AC 476 ms
21,780 KB
testcase_50 AC 440 ms
21,928 KB
testcase_51 AC 424 ms
22,252 KB
testcase_52 AC 419 ms
21,940 KB
testcase_53 AC 433 ms
21,992 KB
testcase_54 AC 478 ms
21,892 KB
testcase_55 AC 420 ms
21,928 KB
testcase_56 AC 428 ms
22,600 KB
testcase_57 AC 475 ms
21,940 KB
testcase_58 AC 501 ms
22,276 KB
testcase_59 AC 440 ms
22,624 KB
testcase_60 AC 444 ms
22,144 KB
testcase_61 AC 434 ms
22,228 KB
testcase_62 AC 415 ms
22,564 KB
testcase_63 AC 438 ms
22,216 KB
testcase_64 AC 469 ms
21,904 KB
testcase_65 AC 422 ms
22,216 KB
testcase_66 AC 420 ms
21,780 KB
testcase_67 AC 465 ms
21,904 KB
testcase_68 AC 468 ms
21,892 KB
testcase_69 AC 446 ms
22,288 KB
testcase_70 AC 444 ms
21,904 KB
testcase_71 AC 438 ms
22,240 KB
testcase_72 AC 434 ms
21,952 KB
testcase_73 AC 468 ms
22,228 KB
testcase_74 AC 476 ms
21,784 KB
testcase_75 AC 442 ms
22,600 KB
testcase_76 AC 424 ms
21,964 KB
testcase_77 AC 490 ms
22,456 KB
testcase_78 AC 419 ms
22,228 KB
testcase_79 AC 423 ms
21,880 KB
testcase_80 AC 430 ms
22,264 KB
testcase_81 AC 412 ms
21,964 KB
testcase_82 AC 412 ms
22,288 KB
testcase_83 AC 416 ms
22,228 KB
testcase_84 AC 441 ms
22,564 KB
testcase_85 AC 411 ms
21,928 KB
testcase_86 AC 432 ms
22,612 KB
testcase_87 AC 456 ms
22,456 KB
testcase_88 AC 413 ms
22,444 KB
testcase_89 AC 444 ms
22,216 KB
testcase_90 AC 440 ms
21,992 KB
testcase_91 AC 432 ms
21,780 KB
testcase_92 AC 422 ms
21,880 KB
testcase_93 AC 406 ms
22,216 KB
testcase_94 AC 444 ms
21,940 KB
testcase_95 AC 428 ms
21,904 KB
testcase_96 AC 417 ms
21,940 KB
testcase_97 AC 493 ms
21,892 KB
testcase_98 AC 466 ms
21,768 KB
testcase_99 AC 452 ms
22,632 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;

#[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)]
enum EdgeState {
    NotEnter,
    NoWall,
    MayBeWall(i32),
}

impl EdgeState {
    #[inline]
    fn prob(&self, p: f64, default: f64) -> f64 {
        let success = 1.0 - p;
        match self {
            EdgeState::NotEnter => default * success,
            EdgeState::NoWall => success,
            EdgeState::MayBeWall(c) => p.powi(*c) * success,
        }
    }
}

// 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 prob_map = gen_prob();

    for trial in 0.. {
        let moves = dijkstra(input, &state, &prob_map);

        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, prob_map: &Map2d<[f64; 4]>) -> 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 diff = (c.row as f64 - c.col as f64).abs();
                let prob = edge
                    .state
                    .prob(input.p, prob_map[c][dir] - 1e-3 * diff)
                    .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][ok ^ 2].state = EdgeState::NoWall;
    }

    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),
    };
    current = current + ADJACENTS[ng];
    state.map[current][ng ^ 2].state = match state.map[current][ng ^ 2].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)
    }
}

fn gen_prob() -> Map2d<[f64; 4]> {
    const TRIAL_COUNT: usize = 200;
    let mut map = Map2d::new(vec![[0.0; 4]; MAP_SIZE * MAP_SIZE], MAP_SIZE);

    for seed in 0..TRIAL_COUNT {
        let rand_map = gen_map(seed as u64 + 42);

        for row in 0..MAP_SIZE {
            for col in 0..MAP_SIZE {
                let c = Coordinate::new(row, col);
                for dir in 0..4 {
                    if rand_map[c][dir].is_some() {
                        map[c][dir] += 1.0 / TRIAL_COUNT as f64;
                    }
                }
            }
        }
    }

    map
}

fn gen_map(seed: u64) -> Map2d<[Option<Coordinate>; 4]> {
    let mut rng = Xorshift::with_seed(seed);
    let wall_count = rng.rand(101) + 100;
    let mut map = Map2d::new(vec![[None; 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 adj in 0..4 {
                let next = c + ADJACENTS[adj];
                if next.in_map(MAP_SIZE) {
                    map[c][adj] = Some(next);
                }
            }
        }
    }

    const U: usize = 0;
    const R: usize = 1;
    const D: usize = 2;
    const L: usize = 3;

    for _ in 0..wall_count {
        loop {
            let d = rng.rand(2);
            if d == 0 {
                let row = rng.rand(MAP_SIZE as u64) as usize;
                let col = rng.rand(MAP_SIZE as u64 - 1) as usize;
                let c = Coordinate::new(row, col);
                let next = c + ADJACENTS[R];

                if map[c][R].is_some() {
                    map[c][R] = None;
                    map[next][L] = None;
                    let mut seen = Map2d::new(vec![false; MAP_SIZE * MAP_SIZE], MAP_SIZE);
                    if dfs(c, &mut seen, &map) == MAP_SIZE * MAP_SIZE {
                        break;
                    }
                    map[c][R] = Some(next);
                    map[next][L] = Some(c);
                }
            } else {
                let row = rng.rand(MAP_SIZE as u64 - 1) as usize;
                let col = rng.rand(MAP_SIZE as u64) as usize;
                let c = Coordinate::new(row, col);
                let next = c + ADJACENTS[D];

                if map[c][D].is_some() {
                    map[c][D] = None;
                    map[next][U] = None;
                    let mut seen = Map2d::new(vec![false; MAP_SIZE * MAP_SIZE], MAP_SIZE);
                    if dfs(c, &mut seen, &map) == MAP_SIZE * MAP_SIZE {
                        break;
                    }
                    map[c][D] = Some(next);
                    map[next][U] = Some(c);
                }
            }
        }
    }

    map
}

fn dfs(current: Coordinate, seen: &mut Map2d<bool>, map: &Map2d<[Option<Coordinate>; 4]>) -> usize {
    let mut count = 1;
    seen[current] = true;

    for dir in 0..4 {
        if let Some(next) = map[current][dir] {
            if seen[next] {
                continue;
            }

            count += dfs(next, seen, map);
        }
    }

    count
}

#[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
    }
}

#[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]
        }
    }
}
0