Submission #39065862
Source Code Expand
extern crate rand;
use rand::Rng;
use std::{
cmp::Reverse,
collections::BinaryHeap,
fmt::{Debug, Formatter},
io::{self, Write},
process,
};
// ---------- Enum, Struct ---------- //
#[derive(Clone, Copy, PartialEq)]
enum Dir {
None = -1,
Up = 0,
Left = 1,
Down = 2,
Right = 3,
}
#[derive(Clone, Copy, PartialEq)]
enum RockState {
None,
Broken,
NotBroken,
Flowing,
}
#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord)]
struct Point {
x: i32,
y: i32,
}
// ---------- Implementation ---------- //
impl Point {
fn new(x: i32, y: i32) -> Point {
Point { x, y }
}
#[allow(dead_code)]
fn mdist(&self, other: &Point) -> i32 {
(self.x - other.x).abs() + (self.y - other.y).abs()
}
fn edist(&self, other: &Point) -> i64 {
((self.x - other.x).pow(2) + (self.y - other.y).pow(2)) as i64
}
}
impl Debug for Dir {
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
match self {
Dir::None => write!(f, "None"),
Dir::Up => write!(f, "Up"),
Dir::Left => write!(f, "Left"),
Dir::Down => write!(f, "Down"),
Dir::Right => write!(f, "Right"),
}
}
}
// ---------- Constants ---------- //
const DX: [i32; 4] = [-1, 0, 1, 0];
const DY: [i32; 4] = [0, -1, 0, 1];
const DX_8: [i32; 8] = [0, 1, 1, 1, 0, -1, -1, -1];
const DY_8: [i32; 8] = [1, 1, 0, -1, -1, -1, 0, 1];
const N: u32 = 200;
const POWER: u32 = 128;
const DFS_WIDTH: i32 = 12;
const BREAK_AC: i32 = 3;
const NEAR_AC: i32 = 15;
// ---------- Functions ---------- //
fn in_range(x: i32, y: i32) -> bool {
x >= 0 && x < N as i32 && y >= 0 && y < N as i32
}
fn query(x: i32, y: i32, p: u32, bedrock: &mut Vec<Vec<(RockState, i32)>>) -> RockState {
if bedrock[x as usize][y as usize].0 == RockState::Broken {
return RockState::Broken;
}
if bedrock[x as usize][y as usize].0 == RockState::Flowing {
return RockState::Flowing;
}
println!("{} {} {}", x, y, p);
io::stdout().flush().unwrap();
let mut input = String::new();
io::stdin().read_line(&mut input).unwrap();
let res = input.trim().parse::<i32>().unwrap();
bedrock[x as usize][y as usize].1 += 1;
if res == -1 || res == 2 {
process::exit(0);
}
if res == 1 {
bedrock[x as usize][y as usize].0 = RockState::Broken
} else {
bedrock[x as usize][y as usize].0 = RockState::NotBroken
}
bedrock[x as usize][y as usize].0
}
fn query_until_broken(
x: i32,
y: i32,
p: u32,
bedrock: &mut Vec<Vec<(RockState, i32)>>,
nxt_state: RockState,
) {
let res = query(x, y, p, bedrock);
if res != RockState::Broken && res != RockState::Flowing {
query_until_broken(x, y, p, bedrock, nxt_state);
}
bedrock[x as usize][y as usize].0 = nxt_state;
}
fn connect_greedy(
src: Point,
target: Point,
bedrock: &mut Vec<Vec<(RockState, i32)>>,
nxt_state: RockState,
) {
let mut x = src.x;
let mut y = src.y;
while x != target.x || y != target.y {
if (x - target.x).abs() > (y - target.y).abs() {
if x < target.x {
query_until_broken(x, y, POWER, bedrock, nxt_state);
x += 1;
} else {
query_until_broken(x, y, POWER, bedrock, nxt_state);
x -= 1;
}
} else {
if y < target.y {
query_until_broken(x, y, POWER, bedrock, nxt_state);
y += 1;
} else {
query_until_broken(x, y, POWER, bedrock, nxt_state);
y -= 1;
}
}
}
query_until_broken(target.x, target.y, POWER, bedrock, nxt_state);
}
fn connect_bfs(src: Point, target: Point, bedrock: &mut Vec<Vec<(RockState, i32)>>) {
let mut que = BinaryHeap::<Reverse<(i32, Point)>>::new();
let mut dist = vec![vec![(1e9 as i32, Point::new(-1, -1)); N as usize]; N as usize];
que.push(Reverse((0, src)));
dist[src.x as usize][src.y as usize].0 = 0;
while let Some(Reverse((dst, now))) = que.pop() {
if now.x == target.x && now.y == target.y {
break;
}
if dst > dist[now.x as usize][now.y as usize].0 {
continue;
}
for i in 0..8 {
let nx = now.x + DFS_WIDTH * DX_8[i];
let ny = now.y + DFS_WIDTH * DY_8[i];
if !in_range(nx, ny) {
continue;
}
let mag = if DX_8[i].abs() + DY_8[i].abs() > 1 {
3
} else {
1
};
let ndst = dst + (bedrock[nx as usize][ny as usize].1) * mag;
if bedrock[nx as usize][ny as usize].0 != RockState::Broken
&& bedrock[nx as usize][ny as usize].0 != RockState::Flowing
{
continue;
}
if ndst < dist[nx as usize][ny as usize].0 {
dist[nx as usize][ny as usize].0 = ndst;
dist[nx as usize][ny as usize].1 = now;
que.push(Reverse((ndst, Point::new(nx, ny))));
}
}
}
let mut now = target;
while now.x != src.x || now.y != src.y {
let prev = dist[now.x as usize][now.y as usize].1;
if prev.x == -1 {
break;
}
connect_greedy(prev, now, bedrock, RockState::Flowing);
now = prev;
}
}
fn dfs(
now: Point,
prev_dir: Dir,
src: Point,
target: Point,
upper_dist: i64,
bedrock: &mut Vec<Vec<(RockState, i32)>>,
visited: &mut Vec<Vec<bool>>,
) -> bool {
let mut rng = rand::thread_rng();
visited[now.x as usize][now.y as usize] = true;
if bedrock[now.x as usize][now.y as usize].0 == RockState::Flowing {
return true;
}
if (now.x - target.x).abs() <= NEAR_AC && (now.y - target.y).abs() <= NEAR_AC {
connect_greedy(now, target, bedrock, RockState::Flowing);
connect_bfs(src, now, bedrock);
return true;
}
let rnddst = ((src.edist(&target) as f64).sqrt() - (now.edist(&target) as f64).sqrt()) / 4.0;
let rnddst2 = ((target.edist(&src) as f64).sqrt() - (now.edist(&src) as f64).sqrt()) / 16.0;
println!("# Source: ({}, {}), Target: ({}, {}), Now: ({}, {}), Dist now: {}, Dist target: {}, rnddst: {}, Exp: {}", src.x, src.y, target.x, target.y, now.x, now.y, now.edist(&target), src.edist(&target), rnddst, rnddst.exp());
if rnddst.exp() < rng.gen::<f64>() || rnddst2.exp() < rng.gen::<f64>() {
return false;
}
let priority_dir: [Dir; 4];
if (now.x - target.x).abs() > (now.y - target.y).abs() {
if now.x > target.x {
if now.y > target.y {
priority_dir = [Dir::Up, Dir::Left, Dir::Right, Dir::Down];
} else {
priority_dir = [Dir::Up, Dir::Right, Dir::Left, Dir::Down];
}
} else {
if now.y > target.y {
priority_dir = [Dir::Down, Dir::Left, Dir::Right, Dir::Up];
} else {
priority_dir = [Dir::Down, Dir::Right, Dir::Left, Dir::Up];
}
}
} else {
if now.y > target.y {
if now.x > target.x {
priority_dir = [Dir::Left, Dir::Up, Dir::Down, Dir::Right];
} else {
priority_dir = [Dir::Left, Dir::Down, Dir::Up, Dir::Right];
}
} else {
if now.x > target.x {
priority_dir = [Dir::Right, Dir::Up, Dir::Down, Dir::Left];
} else {
priority_dir = [Dir::Right, Dir::Down, Dir::Up, Dir::Left];
}
}
}
println!(
"# Source: ({}, {}), Now: ({}, {}), Target: ({}, {}), Priority: [{:?}, {:?}, {:?}, {:?}]",
src.x,
src.y,
now.x,
now.y,
target.x,
target.y,
priority_dir[0],
priority_dir[1],
priority_dir[2],
priority_dir[3]
);
for dir in 0..4 {
let nxt_dir = priority_dir[dir];
if nxt_dir as i32 % 2 == prev_dir as i32 % 2 && nxt_dir != prev_dir {
continue;
}
let nx = now.x + DFS_WIDTH * DX[nxt_dir as usize];
let ny = now.y + DFS_WIDTH * DY[nxt_dir as usize];
if in_range(nx, ny) {
if visited[nx as usize][ny as usize] {
continue;
}
let mut is_broken_tmp = false;
for _ in 0..BREAK_AC {
let res = query(nx, ny, POWER, bedrock);
if res == RockState::Broken {
is_broken_tmp = true;
break;
}
}
if is_broken_tmp {
for dx in -3..3 {
for dy in -3..3 {
let nnx = nx + dx;
let nny = ny + dy;
if in_range(nnx, nny)
&& bedrock[nnx as usize][nny as usize].0 == RockState::Flowing
{
connect_greedy(
Point::new(nx, ny),
Point::new(nnx, nny),
bedrock,
RockState::Flowing,
);
connect_bfs(src, Point::new(nx, ny), bedrock);
return true;
}
}
}
let connected = dfs(
Point::new(nx, ny),
nxt_dir,
src,
target,
upper_dist,
bedrock,
visited,
);
if connected {
return true;
}
}
}
}
false
}
fn input() -> (u32, u32, u32, u32, Vec<Point>, Vec<Point>) {
let (n, w, k, _c) = {
let mut input = String::new();
io::stdin().read_line(&mut input).unwrap();
let mut iter = input.split_whitespace().map(|i| i.parse::<u32>().unwrap());
(
iter.next().unwrap(),
iter.next().unwrap(),
iter.next().unwrap(),
iter.next().unwrap(),
)
};
let wsrc: Vec<Point> = (0..w)
.map(|_| {
let mut input = String::new();
io::stdin().read_line(&mut input).unwrap();
let mut iter = input.split_whitespace().map(|i| i.parse::<i32>().unwrap());
let tmp = Point::new(iter.next().unwrap(), iter.next().unwrap());
tmp
})
.collect();
let house: Vec<Point> = (0..k)
.map(|_| {
let mut input = String::new();
io::stdin().read_line(&mut input).unwrap();
let mut iter = input.split_whitespace().map(|i| i.parse::<i32>().unwrap());
let tmp: Point = Point::new(iter.next().unwrap(), iter.next().unwrap());
tmp
})
.collect();
(n, w, k, _c, wsrc, house)
}
fn main() {
let (n, w, k, _c, wsrc, house) = input();
let mut bedrock = vec![vec![(RockState::None, 0); n as usize]; n as usize];
let mut pq = BinaryHeap::<Reverse<(i64, u32, u32)>>::new();
for i in 0..k {
let mut nearest = 0u32;
for j in 1..w {
let dist = house[i as usize].edist(&wsrc[j as usize]);
if house[i as usize].edist(&wsrc[nearest as usize]) > dist {
nearest = j;
}
}
pq.push(Reverse((
house[i as usize].edist(&wsrc[nearest as usize]),
i,
nearest,
)));
}
while let Some(Reverse((_, i, nearest_idx))) = pq.pop() {
let h = house[i as usize];
if bedrock[h.x as usize][h.y as usize].0 == RockState::Flowing {
continue;
}
let mut should_skip = false;
for dx in -3..3 {
for dy in -3..3 {
let nx = h.x + dx;
let ny = h.y + dy;
if in_range(nx, ny) && bedrock[nx as usize][ny as usize].0 == RockState::Flowing {
connect_greedy(
Point::new(h.x, h.y),
Point::new(nx, ny),
&mut bedrock,
RockState::Flowing,
);
should_skip = true;
break;
}
}
if should_skip {
break;
}
}
if should_skip {
continue;
}
let nearest = if nearest_idx < w {
wsrc[nearest_idx as usize]
} else {
house[(nearest_idx - w) as usize]
};
if bedrock[h.x as usize][h.y as usize].0 == RockState::Broken {
connect_bfs(h, nearest, &mut bedrock);
continue;
}
let mut visited = vec![vec![false; n as usize]; n as usize];
while !dfs(
h,
Dir::None,
h,
nearest,
house[i as usize].edist(&nearest) * 2 as i64,
&mut bedrock,
&mut visited,
) {
for i in 0..n {
for j in 0..n {
visited[i as usize][j as usize] = false;
}
}
}
for j in 0..k {
if i == j {
continue;
}
let dist = house[i as usize].edist(&house[j as usize]);
pq.push(Reverse((dist, j, w + i)));
}
}
assert!(false);
}
Submission Info
| Submission Time |
|
| Task |
A - Excavation |
| User |
a01sa01to |
| Language |
Rust (1.42.0) |
| Score |
8448120 |
| Code Size |
13655 Byte |
| Status |
AC |
| Exec Time |
46 ms |
| Memory |
3836 KiB |
Judge Result
| Set Name |
test_ALL |
| Score / Max Score |
8448120 / 50000000000 |
| 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 |
| Case Name |
Status |
Exec Time |
Memory |
| test_0000.txt |
AC |
28 ms |
3792 KiB |
| test_0001.txt |
AC |
26 ms |
3708 KiB |
| test_0002.txt |
AC |
42 ms |
3788 KiB |
| test_0003.txt |
AC |
24 ms |
3788 KiB |
| test_0004.txt |
AC |
34 ms |
3784 KiB |
| test_0005.txt |
AC |
46 ms |
3716 KiB |
| test_0006.txt |
AC |
32 ms |
3732 KiB |
| test_0007.txt |
AC |
27 ms |
3836 KiB |
| test_0008.txt |
AC |
36 ms |
3688 KiB |
| test_0009.txt |
AC |
28 ms |
3828 KiB |
| test_0010.txt |
AC |
29 ms |
3748 KiB |
| test_0011.txt |
AC |
29 ms |
3732 KiB |
| test_0012.txt |
AC |
28 ms |
3712 KiB |
| test_0013.txt |
AC |
30 ms |
3672 KiB |
| test_0014.txt |
AC |
28 ms |
3800 KiB |
| test_0015.txt |
AC |
29 ms |
3740 KiB |
| test_0016.txt |
AC |
30 ms |
3628 KiB |
| test_0017.txt |
AC |
29 ms |
3676 KiB |
| test_0018.txt |
AC |
32 ms |
3800 KiB |
| test_0019.txt |
AC |
38 ms |
3764 KiB |
| test_0020.txt |
AC |
29 ms |
3768 KiB |
| test_0021.txt |
AC |
32 ms |
3756 KiB |
| test_0022.txt |
AC |
43 ms |
3668 KiB |
| test_0023.txt |
AC |
29 ms |
3688 KiB |
| test_0024.txt |
AC |
28 ms |
3748 KiB |
| test_0025.txt |
AC |
33 ms |
3712 KiB |
| test_0026.txt |
AC |
29 ms |
3756 KiB |
| test_0027.txt |
AC |
24 ms |
3688 KiB |
| test_0028.txt |
AC |
24 ms |
3760 KiB |
| test_0029.txt |
AC |
43 ms |
3832 KiB |
| test_0030.txt |
AC |
30 ms |
3764 KiB |
| test_0031.txt |
AC |
31 ms |
3624 KiB |
| test_0032.txt |
AC |
44 ms |
3800 KiB |
| test_0033.txt |
AC |
34 ms |
3792 KiB |
| test_0034.txt |
AC |
28 ms |
3680 KiB |
| test_0035.txt |
AC |
32 ms |
3800 KiB |
| test_0036.txt |
AC |
37 ms |
3756 KiB |
| test_0037.txt |
AC |
37 ms |
3748 KiB |
| test_0038.txt |
AC |
28 ms |
3792 KiB |
| test_0039.txt |
AC |
36 ms |
3744 KiB |
| test_0040.txt |
AC |
28 ms |
3688 KiB |
| test_0041.txt |
AC |
44 ms |
3760 KiB |
| test_0042.txt |
AC |
38 ms |
3624 KiB |
| test_0043.txt |
AC |
30 ms |
3720 KiB |
| test_0044.txt |
AC |
28 ms |
3716 KiB |
| test_0045.txt |
AC |
23 ms |
3612 KiB |
| test_0046.txt |
AC |
33 ms |
3788 KiB |
| test_0047.txt |
AC |
31 ms |
3792 KiB |
| test_0048.txt |
AC |
35 ms |
3824 KiB |
| test_0049.txt |
AC |
25 ms |
3684 KiB |