알고리즘/문제 풀이
2239번: 스도쿠
Themion
2021. 12. 15. 14:10
https://www.acmicpc.net/problem/2239
2239번: 스도쿠
스도쿠는 매우 간단한 숫자 퍼즐이다. 9×9 크기의 보드가 있을 때, 각 행과 각 열, 그리고 9개의 3×3 크기의 보드에 1부터 9까지의 숫자가 중복 없이 나타나도록 보드를 채우면 된다. 예를 들어 다
www.acmicpc.net
스도쿠의 각 행/열/블록에 어떤 수가 있는지를 추적하면서, 가능한 수를 넣으면서 다음 칸으로 이동하고, 가능한 수가 없다면 현재 칸의 수를 제거한 뒤 이전 칸으로 이동하면 된다.
#include <iostream>
using namespace std;
// row[][i], col[][i], blk[][][i]:
// 주어진 인덱스로 참조하는 행, 열, 3*3에 i가 있는지 여부
bool row[9][10], col[9][10], blk[3][3][10];
// 스도쿠를 플레이하는 판
int sudoku[9][9];
// set(y, x, val, b_set): 좌표 (y, x)에 val값을 b_set이라면 설정, 아니라면 제거
void set(int y, int x, int val, bool b_set) {
sudoku[y][x] = b_set ? val : 0;
row[y][val] = col[x][val] = blk[y / 3][x / 3][val] = b_set;
}
// 백트래킹을 이용해 주어진 인덱스에서 맞는 값을 할당
bool backtrack(int idx) {
// 모든 값에 할당을 성공했다면 true를 반환
if (idx >= 81) return true;
// 현재 인덱스에 이미 값이 있다면 다음 값을 할당
else if (sudoku[idx / 9][idx % 9]) return backtrack(idx + 1);
// 1차원 좌표 idx를 2차원 좌표 (y, x)로 변경
int y = idx / 9, x = idx % 9;
// 1부터 9 중 할당 가능한 값이 있다면
for (int i = 1; i <= 9; i++)
if (!row[y][i] && !col[x][i] && !blk[y / 3][x / 3][i]) {
// 해당 값을 할당한 뒤
set(y, x, i, true);
// 그 값을 포함한 경우가 정답이라면 true를 반환
if (backtrack(idx + 1)) return true;
// 아니라면 해당 값을 제거
else set(y, x, i, false);
}
// 할당에 실패했으므로 false를 반환
return false;
}
int main() {
// 입출력 속도 향상
ios::sync_with_stdio(false);
cin.tie(NULL);
cout.tie(NULL);
// 스도쿠의 각 칸을 입력받을 칸
char buf;
for (int i = 0; i < 9; i++) for (int j = 0; j < 9; j++) {
cin >> buf;
if (buf != '0') set(i, j, buf - '0', true);
}
// 맨 처음 값부터 차례로 할당
backtrack(0);
// 반드시 할당에 성공하는 경우만 주어지므로 정답을 출력
for (int i = 0; i < 9; i++) {
for (int j = 0; j < 9; j++) cout << sudoku[i][j];
cout << '\n';
}
return 0;
}