Solution#
Memo#
- 구현이 귀찮은 것 빼면 그냥 평이한 백트래킹
- 타겟(빈칸)을 따로 추출한다.
- 횡, 종, 중앙값 기준으로 넣을 수 있는 숫자 후보를 추출한다.
- 타겟 배열의 인덱스 기준으로 후보숫자를 전부 넣어보며 백트래킹
// Baekjoon - 2580
// https://www.acmicpc.net/problem/2580
use std::io::{self, Read, Write};
const MAX_LEN: usize = 9;
fn main() {
let mut stdin = io::stdin().lock();
let mut stdout = io::stdout().lock();
let mut input = String::new();
stdin.read_to_string(&mut input).unwrap();
let mut lines = input.lines();
let mut sudoku_board: Vec<Vec<usize>> = vec![];
let mut targets: Vec<(usize, usize)> = vec![];
for i in 0..MAX_LEN {
let tmp: Vec<usize> = lines.next().unwrap()
.split_whitespace()
.map(|x| x.parse::<usize>().unwrap())
.collect();
for j in 0..tmp.len() {
if tmp[j] == 0 {
targets.push((i, j));
}
}
sudoku_board.push(tmp);
}
if solve(&mut sudoku_board, &targets, 0) {
for row in sudoku_board {
let line = row.iter().map(|x| x.to_string()).collect::<Vec<_>>().join(" ");
writeln!(stdout, "{}", line).unwrap();
}
}
}
fn solve(board: &mut [Vec<usize>], targets: &[(usize, usize)], idx: usize) -> bool {
if idx == targets.len() {
return true;
}
let (y, x) = targets[idx];
let mut used = [false; MAX_LEN];
check_horizon(board, &mut used, y);
check_vertical(board, &mut used, x);
check_inside(board, &mut used, (y, x));
for i in 1..=MAX_LEN {
if used[i - 1] {
continue;
}
board[y][x] = i;
if solve(board, targets, idx + 1) {
return true;
}
board[y][x] = 0;
}
false
}
fn check_horizon(board: &[Vec<usize>], used: &mut [bool], y: usize) {
for i in 0..MAX_LEN {
let tmp = board[y][i];
if tmp == 0 {
continue;
}
used[tmp - 1] = true;
}
}
fn check_vertical(board: &[Vec<usize>], used: &mut [bool], x: usize) {
for i in 0..MAX_LEN {
let tmp = board[i][x];
if tmp == 0 {
continue;
}
used[tmp - 1] = true;
}
}
fn check_inside(board: &[Vec<usize>], used: &mut [bool], target: (usize, usize)) {
let block_start_y = (target.0 / 3) * 3;
let block_start_x = (target.1 / 3) * 3;
for dy in 0..3 {
for dx in 0..3 {
let ny = block_start_y + dy;
let nx = block_start_x + dx;
let tmp = board[ny][nx];
if tmp != 0 {
used[tmp - 1] = true;
}
}
}
}