파게로그
[백준 2580번] 스도쿠 본문
문제 링크: 2580번 제목
https://www.acmicpc.net/problem/2580
1. 스도쿠 판을 입력받으면서 빈 칸을 별도의 목록 empty
에 저장한다.
2. empty
의 각 칸에 대해서
2-1. 가능한 숫자의 목록을 구한다.
2-2. 해당 숫자를 집어넣고, 그 다음 칸으로 넘어간다.
2-3-1. 마지막 칸이 아님에도 가능한 숫자가 없다면, 되돌아간다.
2-3-2. 마지막 칸이고 가능한 숫자가 있다면, 첫 숫자를 넣고 종료한다.
되돌아갈 때, 반드시 집어 넣을 숫자를 삭제하여, 즉 다시 0으로 만들어주어 되돌아간 빈 칸에서 '가능한 숫자'가 '불가능한 숫자'가 되지 않도록 주의한다.
import java.util.Scanner;
import java.util.ArrayList;
import java.util.Arrays;
class Pos {
int row;
int col;
Pos(int row, int col) {
this.row = row; this.col = col;
}
}
public class Main {
static int[][] board; // 스도쿠 판
static ArrayList<Pos> empty = new ArrayList<Pos>(); // 빈 칸의 좌표 리스트
/* 스도쿠 판을 인쇄 */
static void printBoard() {
StringBuilder sb = new StringBuilder();
for (int i = 0; i < 9; i++) {
for (int j = 0; j < 9; j++) {
sb.append(board[i][j]);
sb.append(" ");
}
sb.append("\n");
}
System.out.print(sb);
}
/* 수직으로 중복되는 숫자 제거 */
static void vcheck(Pos pos, boolean[] avail) {
Boolean[] nums = new Boolean[10];
Arrays.fill(nums, true);
int curCol = pos.col;
for (int r = 0; r < 9; r++) {
int alreadyInput = board[r][curCol];
nums[alreadyInput] = false;
}
for (int i = 1; i <= 9; i++)
avail[i] = avail[i] && nums[i];
}
/* 수평으로 중복되는 숫자 제거 */
static void hcheck(Pos pos, boolean[] avail) {
Boolean[] nums = new Boolean[10];
Arrays.fill(nums, true);
int curRow = pos.row;
for (int c = 0; c < 9; c++) {
int alreadyInput = board[curRow][c];
nums[alreadyInput] = false;
}
for (int i = 1; i <= 9; i++)
avail[i] = avail[i] && nums[i];
}
/* 3X3 사각형 내에서 중복되는 숫자 제거 */
static void scheck(Pos pos, boolean[] avail) {
Boolean[] nums = new Boolean[10];
Arrays.fill(nums, true);
// 현재 pos가 속한 사각형의 첫 번째 원소의 행과 열
int bsFirstRow = pos.row/3*3;
int bsFirstCol = pos.col/3*3;
for (int r = bsFirstRow; r < bsFirstRow+3; r++) {
for (int c = bsFirstCol; c < bsFirstCol+3; c++) {
int alreadyInput = board[r][c];
nums[alreadyInput] = false;
}
}
for (int i = 1; i <= 9; i++)
avail[i] = avail[i] && nums[i];
}
/* 가능한 숫자가 있는지 확인 */
static boolean availEmpty(boolean[] avail) {
for (int i = 1; i <= 9; i++)
if (avail[i]) return false;
return true;
}
/* empty[emptyIdx]에 가능한 숫자 채우기 */
static void solve(int emptyIdx) {
/* 마지막 빈 칸도 통과했다면 */
// 종료 조건 1 시작: 마지막에 도달
int emptyNum = empty.size();
if (emptyIdx == emptyNum) {
printBoard();
System.exit(0);
};
// 종료 조건 1 끝
/* 마지막 빈 칸 이전이라면 */
// 이번에 숫자를 넣을 빈 칸
Pos pos = empty.get(emptyIdx);
// i가 pos에 들어갈 수 있으면 avail[i]=true
boolean[] avail = new boolean[10];
Arrays.fill(avail, true);
vcheck(pos, avail);
hcheck(pos, avail);
scheck(pos, avail);
// 종료 조건 2 시작: 가능한 숫자가 없음
if (availEmpty(avail)) return;
// 종료 조건 2 끝
// 숫자 넣어보고 다음 위치 호출
for (int i = 1; i <= 9; i++) {
if (avail[i]) { // i가 pos에 들어갈 수 있다면
board[pos.row][pos.col] = i; // i를 집어넣고,
solve(emptyIdx+1); // 다음 빈 칸에 대해서 solve() 호출
board[pos.row][pos.col] = 0; // 빈 칸으로 돌려준다.
}
}
}
public static void main(String[] args) {
board = new int[9][9];
Scanner sc = new Scanner(System.in);
for (int i = 0; i < 9; i++) {
for (int j = 0; j < 9; j++) {
int cur = sc.nextInt();
board[i][j] = cur;
if (cur == 0) empty.add(new Pos(i, j));
// 빈 칸의 좌표를 empty에 추가
}
}
sc.close();
solve(0);
}
}
'콤퓨타 왕왕기초 > PS' 카테고리의 다른 글
[백준 9461번] 파도반 수열 (0) | 2020.11.28 |
---|---|
[백준 1904번] 01타일 (0) | 2020.11.28 |
[프로그래머스 Lv.2] 주식가격 (0) | 2020.11.26 |
[백준 9997번] 폰트 (0) | 2020.11.24 |
[백준 2800번] 괄호 제거 (0) | 2020.11.24 |
Comments