Submission #27966152
Source Code Expand
use grid::Coordinate;
#[allow(unused_imports)]
use proconio::*;
#[allow(unused_imports)]
use rand::prelude::*;
use std::{collections::VecDeque, time::Instant};
#[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),+))
}};
}
#[allow(unused_macros)]
macro_rules! mat {
($e:expr; $d:expr) => { vec![$e; $d] };
($e:expr; $d:expr $(; $ds:expr)+) => { vec![mat![$e $(; $ds)*]; $d] };
}
const N: usize = 20;
const MAX_TURN: usize = 5000;
const TL: f64 = 1.9;
const CANDIDATE_COUNT: usize = 10;
const MAX_INIT_REP: usize = 5;
const U: usize = 0;
const R: usize = 1;
const D: usize = 2;
const L: usize = 3;
#[derive(Debug, Clone)]
struct Input {
n: usize,
start: Coordinate,
graph: Vec<Vec<[Option<Coordinate>; 4]>>,
since: Instant,
}
impl Input {
fn new(start: Coordinate, graph: Vec<Vec<[Option<Coordinate>; 4]>>) -> Self {
let since = Instant::now();
Self {
n: N,
start,
graph,
since,
}
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
#[allow(non_camel_case_types)]
enum Command {
L,
R,
l,
r,
F,
}
impl ToString for Command {
fn to_string(&self) -> String {
match self {
Command::L => String::from("L"),
Command::R => String::from("R"),
Command::l => String::from("l"),
Command::r => String::from("r"),
Command::F => String::from("F"),
}
}
}
enum Operation {
Single(usize, Command),
Multiple(usize, Vec<Operation>),
}
impl Operation {
fn apply(
&self,
input: &Input,
mut coordinate: Coordinate,
mut direction: usize,
mut cleaned: Vec<Vec<bool>>,
mut turn: usize,
) -> (Coordinate, usize, Vec<Vec<bool>>, usize) {
match self {
Operation::Single(rep, command) => {
for _ in 0..*rep {
if turn >= MAX_TURN {
break;
}
let edges = &input.graph[coordinate.row][coordinate.col];
match command {
Command::L => direction = direction.wrapping_sub(1) % 4,
Command::R => direction = (direction + 1) % 4,
Command::l => {
if edges[direction] == None {
direction = direction.wrapping_sub(1) % 4;
}
}
Command::r => {
if edges[direction] == None {
direction = (direction + 1) % 4;
}
}
Command::F => {
if let Some(next) = edges[direction] {
coordinate = next;
cleaned[next.row][next.col] = true;
}
}
}
turn += 1;
}
}
Operation::Multiple(rep, operation) => {
for _ in 0..*rep {
if turn >= MAX_TURN {
break;
}
for op in operation.iter() {
if turn >= MAX_TURN {
break;
}
let (c, d, cl, t) = op.apply(input, coordinate, direction, cleaned, turn);
coordinate = c;
direction = d;
cleaned = cl;
turn = t;
}
}
}
}
(coordinate, direction, cleaned, turn)
}
}
impl ToString for Operation {
fn to_string(&self) -> String {
match self {
Operation::Single(rep, command) => {
let mut str = String::new();
if *rep > 1 {
for c in rep.to_string().chars() {
str.push(c);
}
}
for c in command.to_string().chars() {
str.push(c);
}
str
}
Operation::Multiple(rep, operation) => {
let mut str = String::new();
if *rep > 1 {
for c in rep.to_string().chars() {
str.push(c);
}
str.push('(');
}
for op in operation.iter() {
for c in op.to_string().chars() {
str.push(c);
}
}
if *rep > 1 {
str.push(')');
}
str
}
}
}
}
fn main() {
let input = read_input();
let operation = solve(&input);
println!("{}", operation.to_string());
eprintln!("{}", calc_score(&input, &operation));
}
fn read_input() -> Input {
input! {
s_row: usize,
s_col: usize,
}
let start = Coordinate::new(s_row, s_col);
let mut graph = mat![[None; 4]; N; N];
for row in 0..N {
input! {
s: String
}
for (col, c) in s.chars().enumerate() {
if c == '0' {
graph[row][col][R] = Some(Coordinate::new(row, col + 1));
graph[row][col + 1][L] = Some(Coordinate::new(row, col));
}
}
}
for row in 0..(N - 1) {
input! {
s: String
}
for (col, c) in s.chars().enumerate() {
if c == '0' {
graph[row][col][D] = Some(Coordinate::new(row + 1, col));
graph[row + 1][col][U] = Some(Coordinate::new(row, col));
}
}
}
let input = Input::new(start, graph);
input
}
fn solve(input: &Input) -> Operation {
let distances = calc_dists(input);
let actual_distances = calc_actual_dists(input);
let init_operation_candidates =
get_init_operation_candidates(input, &distances, &actual_distances);
let remainining_time = TL - (Instant::now() - input.since).as_secs_f64();
let each_duration = remainining_time / init_operation_candidates.len() as f64;
let mut best_score = std::i32::MAX;
let mut best_init_operation = Operation::Single(1, Command::F);
let mut best_tsp_perm = vec![];
for init_operation in init_operation_candidates {
let (init_coordinate, init_direction, cleaned) = generate_init_state(input);
let (init_coordinate, init_direction, cleaned, _) =
init_operation.apply(input, init_coordinate, init_direction, cleaned, 0);
let unvisited = get_unvisited(&cleaned);
if unvisited.len() == 0 {
return init_operation;
}
let (tsp_perm, score) = tsp_annealing(
init_coordinate,
init_direction,
&unvisited,
&distances,
&actual_distances,
each_duration,
);
if chmin!(best_score, score) {
best_init_operation = init_operation;
best_tsp_perm = tsp_perm;
}
}
let (init_coordinate, init_direction, cleaned) = generate_init_state(input);
let (init_coordinate, init_direction, cleaned, _) =
best_init_operation.apply(input, init_coordinate, init_direction, cleaned, 0);
let unvisited = get_unvisited(&cleaned);
let after_operation = get_operation(
input,
init_coordinate,
init_direction,
0,
&unvisited,
&best_tsp_perm,
);
Operation::Multiple(1, vec![best_init_operation, after_operation])
}
fn get_init_operation_candidates(
input: &Input,
distances: &[Vec<i32>],
actual_distances: &[Vec<i32>],
) -> Vec<Operation> {
let mut candidates = vec![];
for operation in generate_init_candidates() {
let score = estimate_score(input, &operation, distances, actual_distances);
candidates.push((score, operation));
}
candidates.sort_by(|a, b| b.0.cmp(&a.0));
while candidates.len() > CANDIDATE_COUNT {
candidates.pop();
}
candidates.drain(..).map(|(_, op)| op).collect()
}
fn estimate_score(
input: &Input,
init_operation: &Operation,
distances: &[Vec<i32>],
actual_distances: &[Vec<i32>],
) -> i32 {
let (init_coordinate, init_direction, cleaned) = generate_init_state(input);
let (mut coordinate, mut direction, cleaned, _) =
init_operation.apply(input, init_coordinate, init_direction, cleaned, 0);
let unvisited = get_unvisited(&cleaned);
if unvisited.len() == 0 {
return calc_score(input, init_operation);
}
let (tsp_perm, _) = tsp_nn(
coordinate,
direction,
&unvisited,
&distances,
&actual_distances,
);
let mut after_length = 0;
let mut actual_length = 0;
match init_operation {
Operation::Single(_, _) => unreachable!(),
Operation::Multiple(rep, ops) => {
for op in ops.iter() {
match op {
Operation::Single(_, _) => unreachable!(),
Operation::Multiple(rep, op) => actual_length += (rep * op.len()) as i32,
}
}
actual_length *= *rep as i32;
}
}
let mut flag = 0;
for &(next_index, next_direction, next_flag) in tsp_perm.iter() {
let next_coordinate = unvisited[next_index];
let from = to_index(coordinate.row, coordinate.col, direction, flag);
let to = to_index(
next_coordinate.row,
next_coordinate.col,
next_direction,
next_flag,
);
after_length += distances[from][to];
actual_length += actual_distances[from][to];
coordinate = next_coordinate;
direction = next_direction;
flag = next_flag;
}
// なんかおかしい
if actual_length + 5 <= MAX_TURN as i32 {
return -(init_operation.to_string().len() as i32 + after_length);
} else {
return std::i32::MIN;
}
}
fn generate_init_state(input: &Input) -> (Coordinate, usize, Vec<Vec<bool>>) {
let coordinate = input.start;
let direction = U;
let mut cleaned = mat![false; N; N];
cleaned[coordinate.row][coordinate.col] = true;
(coordinate, direction, cleaned)
}
fn generate_init_candidates() -> Vec<Operation> {
let mut candidates = vec![];
let init_turns = vec![
4750, 4760, 4770, 4780, 4790, 4800, 4810, 4820, 4830, 4840, 4850, 4860, 4870, 4880, 4890,
4900, 4910, 4920, 4930,
];
for init_turn in init_turns {
for left in 1..=MAX_INIT_REP {
for right in 1..=MAX_INIT_REP {
let rep = init_turn / (4 * (left + right));
let operation = Operation::Multiple(
rep,
vec![
Operation::Multiple(
left,
vec![
Operation::Single(1, Command::L),
Operation::Single(1, Command::r),
Operation::Single(1, Command::r),
Operation::Single(1, Command::F),
],
),
Operation::Multiple(
right,
vec![
Operation::Single(1, Command::R),
Operation::Single(1, Command::l),
Operation::Single(1, Command::l),
Operation::Single(1, Command::F),
],
),
],
);
candidates.push(operation);
let operation = Operation::Multiple(
rep,
vec![
Operation::Multiple(
right,
vec![
Operation::Single(1, Command::R),
Operation::Single(1, Command::l),
Operation::Single(1, Command::l),
Operation::Single(1, Command::F),
],
),
Operation::Multiple(
left,
vec![
Operation::Single(1, Command::L),
Operation::Single(1, Command::r),
Operation::Single(1, Command::r),
Operation::Single(1, Command::F),
],
),
],
);
candidates.push(operation);
}
}
}
candidates
}
fn calc_dists(input: &Input) -> Vec<Vec<i32>> {
const LENGTH: usize = N * N * 4 * 3;
let mut distances = mat![0; LENGTH; LENGTH];
for row in 0..N {
for col in 0..N {
let coordinate = Coordinate::new(row, col);
for dir in 0..4 {
for flag in 0..3 {
let index = to_index(row, col, dir, flag);
let distances = &mut distances[index];
let dists = calc_dist(input, coordinate, dir, flag);
let mut index = 0;
for row in 0..N {
for col in 0..N {
for dir in 0..4 {
for flag in 0..3 {
distances[index] = dists[row][col][dir][flag];
index += 1;
}
}
}
}
}
}
}
}
distances
}
fn calc_dist(
input: &Input,
start_coordinate: Coordinate,
start_direction: usize,
flag: usize,
) -> Vec<Vec<[[i32; 3]; 4]>> {
let mut distances = mat![[[100000000; 3]; 4]; N; N];
let mut queue = VecDeque::new();
distances[start_coordinate.row][start_coordinate.col][start_direction][flag] = 0;
queue.push_back((
start_coordinate.row,
start_coordinate.col,
start_direction,
flag,
));
while let Some((row, col, dir, flag)) = queue.pop_front() {
let dist = distances[row][col][dir][flag];
// Forward
if let Some(next) = input.graph[row][col][dir] {
// 9 -> 10の時は考慮できないけどええやろ
if flag == 2 {
if chmin!(distances[next.row][next.col][dir][flag], dist) {
queue.push_front((next.row, next.col, dir, flag));
}
} else if flag < 2 {
if chmin!(distances[next.row][next.col][dir][flag + 1], dist + 1) {
queue.push_back((next.row, next.col, dir, flag + 1));
}
}
}
// Left
let next_dir = dir.wrapping_sub(1) % 4;
if chmin!(distances[row][col][next_dir][0], dist + 1) {
queue.push_back((row, col, next_dir, 0));
}
// Right
let next_dir = (dir + 1) % 4;
if chmin!(distances[row][col][next_dir][0], dist + 1) {
queue.push_back((row, col, next_dir, 0));
}
}
distances
}
fn calc_actual_dists(input: &Input) -> Vec<Vec<i32>> {
const LENGTH: usize = N * N * 4 * 3;
let mut distances = mat![0; LENGTH; LENGTH];
for row in 0..N {
for col in 0..N {
let coordinate = Coordinate::new(row, col);
for dir in 0..4 {
for flag in 0..3 {
let index = to_index(row, col, dir, flag);
let distances = &mut distances[index];
let dists = calc_actual_dist(input, coordinate, dir, flag);
let mut index = 0;
for row in 0..N {
for col in 0..N {
for dir in 0..4 {
for flag in 0..3 {
distances[index] = dists[row][col][dir][flag];
index += 1;
}
}
}
}
}
}
}
}
distances
}
fn calc_actual_dist(
input: &Input,
start_coordinate: Coordinate,
start_direction: usize,
flag: usize,
) -> Vec<Vec<[[i32; 3]; 4]>> {
let mut distances = mat![[[100000000; 3]; 4]; N; N];
let mut queue = VecDeque::new();
distances[start_coordinate.row][start_coordinate.col][start_direction][flag] = 0;
queue.push_back((
start_coordinate.row,
start_coordinate.col,
start_direction,
flag,
));
while let Some((row, col, dir, flag)) = queue.pop_front() {
let dist = distances[row][col][dir][flag];
// Forward
if let Some(next) = input.graph[row][col][dir] {
let next_flag = (flag + 1).min(2);
if chmin!(distances[next.row][next.col][dir][next_flag], dist + 1) {
queue.push_back((next.row, next.col, dir, next_flag));
}
}
// Left
let next_dir = dir.wrapping_sub(1) % 4;
if chmin!(distances[row][col][next_dir][0], dist + 1) {
queue.push_back((row, col, next_dir, 0));
}
// Right
let next_dir = (dir + 1) % 4;
if chmin!(distances[row][col][next_dir][0], dist + 1) {
queue.push_back((row, col, next_dir, 0));
}
}
distances
}
fn get_unvisited(cleaned: &[Vec<bool>]) -> Vec<Coordinate> {
let mut unvisited = vec![];
for row in 0..N {
for col in 0..N {
if !cleaned[row][col] {
unvisited.push(Coordinate::new(row, col));
}
}
}
unvisited
}
fn tsp_nn(
mut coordinate: Coordinate,
mut direction: usize,
to_visits: &[Coordinate],
distances: &[Vec<i32>],
actual_distances: &[Vec<i32>],
) -> (Vec<(usize, usize, usize)>, i32) {
let mut visited = vec![false; to_visits.len()];
let mut flag = 0;
let mut results = Vec::with_capacity(to_visits.len());
let mut dist = 0;
// とりあえずNearest Neighbor
for _ in 0..visited.len() {
let dists = &distances[to_index(coordinate.row, coordinate.col, direction, flag)];
let dists_act =
&actual_distances[to_index(coordinate.row, coordinate.col, direction, flag)];
let mut best_dist = std::i32::MAX;
let mut best_actual_dist = std::i32::MAX;
let mut best_index = 0;
let mut best_dir = 0;
let mut best_flag = 0;
for (i, next) in to_visits.iter().enumerate() {
if visited[i] {
continue;
}
for dir in 0..4 {
for fl in 0..3 {
let d = dists[to_index(next.row, next.col, dir, fl)];
let d_act = dists_act[to_index(next.row, next.col, dir, fl)];
if chmin!(best_dist, d) {
best_actual_dist = d_act;
best_index = i;
best_dir = dir;
best_flag = fl;
} else if best_dist == d && chmin!(best_actual_dist, d_act) {
best_index = i;
best_dir = dir;
best_flag = fl;
} else if best_dist == d && best_actual_dist == d_act && chmax!(best_flag, fl) {
best_index = i;
best_dir = dir;
}
}
}
}
results.push((best_index, best_dir, best_flag));
coordinate = to_visits[best_index];
direction = best_dir;
flag = best_flag;
visited[best_index] = true;
dist += best_dist;
}
(results, dist)
}
fn tsp_annealing(
init_coordinate: Coordinate,
init_direction: usize,
to_visits: &[Coordinate],
distances: &[Vec<i32>],
actual_distances: &[Vec<i32>],
duration: f64,
) -> (Vec<(usize, usize, usize)>, i32) {
let (init_solution, init_score) = tsp_nn(
init_coordinate,
init_direction,
to_visits,
distances,
actual_distances,
);
if init_solution.len() <= 2 {
return (init_solution, init_score);
}
let mut solution = init_solution.clone();
let mut best_solution = solution.clone();
let mut current_score = init_score;
let mut best_score = current_score;
let since = Instant::now();
let duration_inv = 1.0 / duration;
let mut all_iter = 0;
let mut valid_iter = 0;
let mut accepted_count = 0;
let mut update_count = 0;
let mut rng = rand_pcg::Pcg64Mcg::new(42);
let temp0 = 5e0;
let temp1 = 1e-1;
while (Instant::now() - since).as_secs_f64() < duration {
all_iter += 1;
let time = (std::time::Instant::now() - since).as_secs_f64() * duration_inv;
let temp = f64::powf(temp0, 1.0 - time) * f64::powf(temp1, time);
// 変形
let mut new_perm = solution
.iter()
.map(|&(index, _, _)| index)
.collect::<Vec<_>>();
let left = rng.gen_range(0, new_perm.len() - 1);
let right = rng.gen_range(left + 2, new_perm.len() + 1);
new_perm[left..right].reverse();
let mut coordinate = init_coordinate;
let mut direction = init_direction;
let mut flag = 0;
let mut new_solution = Vec::with_capacity(solution.len());
let mut new_score = 0;
for &index in new_perm.iter() {
let dists = &distances[to_index(coordinate.row, coordinate.col, direction, flag)];
let dists_act =
&actual_distances[to_index(coordinate.row, coordinate.col, direction, flag)];
let mut best_dist = std::i32::MAX;
let mut best_actual_dist = std::i32::MAX;
let mut best_dir = 0;
let mut best_flag = 0;
let next = to_visits[index];
for dir in 0..4 {
for fl in 0..3 {
let d = dists[to_index(next.row, next.col, dir, fl)];
let d_act = dists_act[to_index(next.row, next.col, dir, fl)];
if chmin!(best_dist, d) {
best_actual_dist = d_act;
best_dir = dir;
best_flag = fl;
} else if best_dist == d && chmin!(best_actual_dist, d_act) {
best_dir = dir;
best_flag = fl;
} else if best_dist == d && best_actual_dist == d_act && chmax!(best_flag, fl) {
best_dir = dir;
}
}
}
new_score += best_dist;
new_solution.push((index, best_dir, best_flag));
coordinate = next;
direction = best_dir;
flag = best_flag;
}
// スコア計算
let score_diff = new_score - current_score;
if score_diff <= 0 || rng.gen_bool(f64::exp(-score_diff as f64 / temp)) {
// 解の更新
current_score = new_score;
solution = new_solution;
accepted_count += 1;
if chmin!(best_score, new_score) {
update_count += 1;
best_solution = solution.clone();
}
}
valid_iter += 1;
}
eprintln!("===== annealing =====");
eprintln!("init_score : {}", init_score);
eprintln!("score : {}", best_score);
eprintln!("all iter : {}", all_iter);
eprintln!("valid iter : {}", valid_iter);
eprintln!("accepted : {}", accepted_count);
eprintln!("updated : {}", update_count);
eprintln!("");
(best_solution, best_score)
}
fn get_operation(
input: &Input,
mut coordinate: Coordinate,
mut dir: usize,
mut flag: usize,
unvisited: &[Coordinate],
tsp: &[(usize, usize, usize)],
) -> Operation {
let mut commands = vec![];
for &(i, next_dir, next_flag) in tsp.iter() {
let next_coordinate = unvisited[i];
let next_commands = get_command(
input,
coordinate,
dir,
flag,
next_coordinate,
next_dir,
next_flag,
);
for cmd in next_commands {
commands.push(cmd);
}
coordinate = next_coordinate;
dir = next_dir;
flag = next_flag;
}
compress_commands(&commands)
}
fn get_command(
input: &Input,
start_coordinate: Coordinate,
start_dir: usize,
start_flag: usize,
goal_coordinate: Coordinate,
goal_dir: usize,
goal_flag: usize,
) -> Vec<Command> {
let mut distances = mat![[[100000000; 3]; 4]; N; N];
let mut from = mat![[[(Coordinate::new(0, 0), 0, 0, Command::F); 3]; 4]; N; N];
let mut queue = VecDeque::new();
distances[start_coordinate.row][start_coordinate.col][start_dir][start_flag] = 0;
queue.push_back((
start_coordinate.row,
start_coordinate.col,
start_dir,
start_flag,
));
while let Some((row, col, dir, flag)) = queue.pop_front() {
let dist = distances[row][col][dir][flag];
let current = Coordinate::new(row, col);
// Forward
if let Some(next) = input.graph[row][col][dir] {
// 9 -> 10の時は考慮できないけどええやろ
if flag == 2 {
if chmin!(distances[next.row][next.col][dir][flag], dist) {
from[next.row][next.col][dir][flag] = (current, dir, flag, Command::F);
queue.push_front((next.row, next.col, dir, flag));
}
} else if flag < 2 {
if chmin!(distances[next.row][next.col][dir][flag + 1], dist + 1) {
from[next.row][next.col][dir][flag + 1] = (current, dir, flag, Command::F);
queue.push_back((next.row, next.col, dir, flag + 1));
}
}
}
// Left
let next_dir = dir.wrapping_sub(1) % 4;
if chmin!(distances[row][col][next_dir][0], dist + 1) {
from[row][col][next_dir][0] = (current, dir, flag, Command::L);
queue.push_back((row, col, next_dir, 0));
}
// Right
let next_dir = (dir + 1) % 4;
if chmin!(distances[row][col][next_dir][0], dist + 1) {
from[row][col][next_dir][0] = (current, dir, flag, Command::R);
queue.push_back((row, col, next_dir, 0));
}
}
let mut current = goal_coordinate;
let mut dir = goal_dir;
let mut flag = goal_flag;
let mut commands = Vec::with_capacity(distances[current.row][current.col][dir][flag]);
while start_coordinate != current || start_dir != dir || start_flag != flag {
let (c, d, f, com) = from[current.row][current.col][dir][flag];
commands.push(com);
current = c;
dir = d;
flag = f;
}
commands.reverse();
commands
}
fn compress_commands(commands: &[Command]) -> Operation {
let mut last_command = commands[0];
let mut rep_count = 1;
let mut operations = vec![];
for &command in commands.iter().skip(1) {
if last_command != command {
operations.push(Operation::Single(rep_count, last_command));
last_command = command;
rep_count = 1;
} else {
rep_count += 1;
}
}
operations.push(Operation::Single(rep_count, last_command));
Operation::Multiple(1, operations)
}
fn calc_score(input: &Input, operation: &Operation) -> i32 {
let (coordinate, direction, cleaned) = generate_init_state(input);
let (_, _, cleaned_result, _) = operation.apply(input, coordinate, direction, cleaned, 0);
let cleaned_count = cleaned_result
.iter()
.map(|v| v.iter().filter(|&&b| b).count())
.sum::<usize>();
if cleaned_count < N * N {
cleaned_count as i32
} else {
let len = operation.to_string().len() as f64;
let score = (N * N) as i32 + (1e8 / (100.0 + len)).round() as i32;
score
}
}
fn to_index(row: usize, col: usize, dir: usize, flag: usize) -> usize {
(((row * N + col) * 4 + dir) * 3) + flag
}
#[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
}
}
#[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),
];
}
Submission Info
Judge Result
| Set Name |
test_ALL |
| Score / Max Score |
55682429 / 100000000 |
| Status |
|
| Set Name |
Test Cases |
| test_ALL |
test_0000.txt, test_0001.txt, test_0002.txt, test_0003.txt, test_0004.txt, test_0005.txt, test_0006.txt, test_0007.txt, test_0008.txt, test_0009.txt, test_0010.txt, test_0011.txt, test_0012.txt, test_0013.txt, test_0014.txt, test_0015.txt, test_0016.txt, test_0017.txt, test_0018.txt, test_0019.txt, test_0020.txt, test_0021.txt, test_0022.txt, test_0023.txt, test_0024.txt, test_0025.txt, test_0026.txt, test_0027.txt, test_0028.txt, test_0029.txt, test_0030.txt, test_0031.txt, test_0032.txt, test_0033.txt, test_0034.txt, test_0035.txt, test_0036.txt, test_0037.txt, test_0038.txt, test_0039.txt, test_0040.txt, test_0041.txt, test_0042.txt, test_0043.txt, test_0044.txt, test_0045.txt, test_0046.txt, test_0047.txt, test_0048.txt, test_0049.txt, test_0050.txt, test_0051.txt, test_0052.txt, test_0053.txt, test_0054.txt, test_0055.txt, test_0056.txt, test_0057.txt, test_0058.txt, test_0059.txt, test_0060.txt, test_0061.txt, test_0062.txt, test_0063.txt, test_0064.txt, test_0065.txt, test_0066.txt, test_0067.txt, test_0068.txt, test_0069.txt, test_0070.txt, test_0071.txt, test_0072.txt, test_0073.txt, test_0074.txt, test_0075.txt, test_0076.txt, test_0077.txt, test_0078.txt, test_0079.txt, test_0080.txt, test_0081.txt, test_0082.txt, test_0083.txt, test_0084.txt, test_0085.txt, test_0086.txt, test_0087.txt, test_0088.txt, test_0089.txt, test_0090.txt, test_0091.txt, test_0092.txt, test_0093.txt, test_0094.txt, test_0095.txt, test_0096.txt, test_0097.txt, test_0098.txt, test_0099.txt |
| Case Name |
Status |
Exec Time |
Memory |
| test_0000.txt |
AC |
1913 ms |
183952 KiB |
| test_0001.txt |
AC |
1914 ms |
184028 KiB |
| test_0002.txt |
AC |
1914 ms |
184040 KiB |
| test_0003.txt |
AC |
1914 ms |
183916 KiB |
| test_0004.txt |
AC |
1914 ms |
184156 KiB |
| test_0005.txt |
AC |
1915 ms |
184108 KiB |
| test_0006.txt |
AC |
1912 ms |
183940 KiB |
| test_0007.txt |
AC |
1914 ms |
184092 KiB |
| test_0008.txt |
AC |
1914 ms |
184004 KiB |
| test_0009.txt |
AC |
1915 ms |
184052 KiB |
| test_0010.txt |
AC |
1913 ms |
184000 KiB |
| test_0011.txt |
AC |
1913 ms |
184156 KiB |
| test_0012.txt |
AC |
1913 ms |
183992 KiB |
| test_0013.txt |
AC |
1914 ms |
183924 KiB |
| test_0014.txt |
AC |
1914 ms |
184068 KiB |
| test_0015.txt |
AC |
1914 ms |
184124 KiB |
| test_0016.txt |
AC |
1913 ms |
183908 KiB |
| test_0017.txt |
AC |
1913 ms |
184084 KiB |
| test_0018.txt |
AC |
1914 ms |
184104 KiB |
| test_0019.txt |
AC |
1914 ms |
184104 KiB |
| test_0020.txt |
AC |
1913 ms |
184096 KiB |
| test_0021.txt |
AC |
1916 ms |
184012 KiB |
| test_0022.txt |
AC |
1913 ms |
184036 KiB |
| test_0023.txt |
AC |
1913 ms |
184060 KiB |
| test_0024.txt |
AC |
1913 ms |
184020 KiB |
| test_0025.txt |
AC |
1913 ms |
184224 KiB |
| test_0026.txt |
AC |
1913 ms |
184092 KiB |
| test_0027.txt |
AC |
1913 ms |
184084 KiB |
| test_0028.txt |
AC |
1913 ms |
184024 KiB |
| test_0029.txt |
AC |
1913 ms |
184024 KiB |
| test_0030.txt |
AC |
1913 ms |
184084 KiB |
| test_0031.txt |
AC |
1912 ms |
183940 KiB |
| test_0032.txt |
AC |
1913 ms |
183960 KiB |
| test_0033.txt |
AC |
1913 ms |
184008 KiB |
| test_0034.txt |
AC |
1914 ms |
184136 KiB |
| test_0035.txt |
AC |
1913 ms |
183904 KiB |
| test_0036.txt |
AC |
1913 ms |
184204 KiB |
| test_0037.txt |
AC |
1914 ms |
184020 KiB |
| test_0038.txt |
AC |
1913 ms |
183900 KiB |
| test_0039.txt |
AC |
1913 ms |
184128 KiB |
| test_0040.txt |
AC |
1913 ms |
184120 KiB |
| test_0041.txt |
AC |
1913 ms |
184208 KiB |
| test_0042.txt |
AC |
1913 ms |
184028 KiB |
| test_0043.txt |
AC |
1913 ms |
184140 KiB |
| test_0044.txt |
AC |
1915 ms |
184092 KiB |
| test_0045.txt |
AC |
1913 ms |
184220 KiB |
| test_0046.txt |
AC |
1914 ms |
183968 KiB |
| test_0047.txt |
AC |
1913 ms |
183856 KiB |
| test_0048.txt |
AC |
1913 ms |
183900 KiB |
| test_0049.txt |
AC |
1913 ms |
183964 KiB |
| test_0050.txt |
AC |
1913 ms |
184072 KiB |
| test_0051.txt |
AC |
1154 ms |
183380 KiB |
| test_0052.txt |
AC |
1914 ms |
183992 KiB |
| test_0053.txt |
AC |
1913 ms |
184220 KiB |
| test_0054.txt |
AC |
1913 ms |
183860 KiB |
| test_0055.txt |
AC |
1913 ms |
184140 KiB |
| test_0056.txt |
AC |
1913 ms |
183904 KiB |
| test_0057.txt |
AC |
1912 ms |
184028 KiB |
| test_0058.txt |
AC |
1914 ms |
184224 KiB |
| test_0059.txt |
AC |
1913 ms |
183940 KiB |
| test_0060.txt |
AC |
1913 ms |
184196 KiB |
| test_0061.txt |
AC |
1913 ms |
184124 KiB |
| test_0062.txt |
AC |
1916 ms |
184144 KiB |
| test_0063.txt |
AC |
1912 ms |
183924 KiB |
| test_0064.txt |
AC |
1913 ms |
184052 KiB |
| test_0065.txt |
AC |
1917 ms |
184036 KiB |
| test_0066.txt |
AC |
1914 ms |
184172 KiB |
| test_0067.txt |
AC |
1915 ms |
183956 KiB |
| test_0068.txt |
AC |
1913 ms |
183868 KiB |
| test_0069.txt |
AC |
1913 ms |
184080 KiB |
| test_0070.txt |
AC |
1913 ms |
184072 KiB |
| test_0071.txt |
AC |
1913 ms |
184016 KiB |
| test_0072.txt |
AC |
1912 ms |
184144 KiB |
| test_0073.txt |
AC |
1914 ms |
184016 KiB |
| test_0074.txt |
AC |
1914 ms |
184100 KiB |
| test_0075.txt |
AC |
1913 ms |
184028 KiB |
| test_0076.txt |
AC |
1017 ms |
183468 KiB |
| test_0077.txt |
AC |
1913 ms |
183908 KiB |
| test_0078.txt |
AC |
1914 ms |
184008 KiB |
| test_0079.txt |
AC |
1914 ms |
183908 KiB |
| test_0080.txt |
AC |
1913 ms |
183940 KiB |
| test_0081.txt |
AC |
1913 ms |
184004 KiB |
| test_0082.txt |
AC |
1914 ms |
184012 KiB |
| test_0083.txt |
AC |
1913 ms |
183924 KiB |
| test_0084.txt |
AC |
1326 ms |
183472 KiB |
| test_0085.txt |
AC |
1912 ms |
184068 KiB |
| test_0086.txt |
AC |
1914 ms |
183924 KiB |
| test_0087.txt |
AC |
1912 ms |
184084 KiB |
| test_0088.txt |
AC |
1914 ms |
184072 KiB |
| test_0089.txt |
AC |
1914 ms |
184132 KiB |
| test_0090.txt |
AC |
1913 ms |
184092 KiB |
| test_0091.txt |
AC |
1913 ms |
183956 KiB |
| test_0092.txt |
AC |
1912 ms |
183912 KiB |
| test_0093.txt |
AC |
1913 ms |
184056 KiB |
| test_0094.txt |
AC |
1913 ms |
184092 KiB |
| test_0095.txt |
AC |
1913 ms |
183992 KiB |
| test_0096.txt |
AC |
1914 ms |
184032 KiB |
| test_0097.txt |
AC |
1914 ms |
183964 KiB |
| test_0098.txt |
AC |
1913 ms |
184132 KiB |
| test_0099.txt |
AC |
1914 ms |
183924 KiB |