Solution#
Memo#
dp[y][x][state] = ways
- 지금 파이프 끝의 좌표와 상태에 도달할 수 있는 경우를 바텀업 방식으로 dp
#[allow(clippy::all)]
#[allow(unused_must_use, unused_doc_comments)]
fn solve<R: BufRead, W: Write>(io: &mut IO<R, W>) -> Option<()> {
let n = io.get(0usize)?;
let grid = io.get(vec![vec![0usize; n]; n])?;
// 0 - horizontal, 1 - vertical, 2 - diagonal
// dp[i][j][파이프상태] = 경우의 수
let mut dp = vec![vec![vec![0usize; 3]; n]; n];
// 초기 상태: (0, 1)에 horizontal 파이프
dp[0][1][0] = 1;
for i in 0..n {
for j in 0..n {
if grid[i][j] == 1 { continue; } // 벽인 경우 건너뛰기
// 현재 위치에서 가능한 각 상태에 대해
for state in 0..3 {
if dp[i][j][state] == 0 { continue; }
// 다음 가능한 이동들 계산
let moves = get_possible_moves(&grid, i, j, n, state);
for PipeState(next_state, ny, nx) in moves {
dp[ny][nx][next_state] += dp[i][j][state];
}
}
}
}
// 목표 지점 (n-1, n-1)에 도달하는 모든 경우의 수 합산
let result = dp[n - 1][n - 1][0] + dp[n - 1][n - 1][1] + dp[n - 1][n - 1][2];
io.put(result).nl();
None
}
struct PipeState(usize, usize, usize); // (state, y, x)
fn get_possible_moves(
grid: &[Vec<usize>],
y: usize,
x: usize,
max_size: usize,
current_state: usize,
) -> Vec<PipeState> {
let mut moves = Vec::new();
let right = x + 1 < max_size && grid[y][x + 1] == 0;
let down = y + 1 < max_size && grid[y + 1][x] == 0;
let diag = x + 1 < max_size && y + 1 < max_size &&
grid[y][x + 1] == 0 && grid[y + 1][x] == 0 && grid[y + 1][x + 1] == 0;
// 수평 이동 (현재가 수평 또는 대각선일 때)
if right && (current_state == 0 || current_state == 2) {
moves.push(PipeState(0, y, x + 1));
}
// 수직 이동 (현재가 수직 또는 대각선일 때)
if down && (current_state == 1 || current_state == 2) {
moves.push(PipeState(1, y + 1, x));
}
// 대각선 이동 (모든 상태에서 가능)
if diag {
moves.push(PipeState(2, y + 1, x + 1));
}
moves
}