파이썬 / BOJ 백준 / 2580 스도쿠 - 백트래킹
https://www.acmicpc.net/problem/2580
문제
스도쿠는 18세기 스위스 수학자가 만든 '라틴 사각형'이랑 퍼즐에서 유래한 것으로 현재 많은 인기를 누리고 있다. 이 게임은 아래 그림과 같이 가로, 세로 각각 9개씩 총 81개의 작은 칸으로 이루어진 정사각형 판 위에서 이뤄지는데, 게임 시작 전 일부 칸에는 1부터 9까지의 숫자 중 하나가 쓰여 있다.
나머지 빈 칸을 채우는 방식은 다음과 같다.
각각의 가로줄과 세로줄에는 1부터 9까지의 숫자가 한 번씩만 나타나야 한다.
굵은 선으로 구분되어 있는 3x3 정사각형 안에도 1부터 9까지의 숫자가 한 번씩만 나타나야 한다.
위의 예의 경우, 첫째 줄에는 1을 제외한 나머지 2부터 9까지의 숫자들이 이미 나타나 있으므로 첫째 줄 빈칸에는 1이 들어가야 한다.
또한 위쪽 가운데 위치한 3x3 정사각형의 경우에는 3을 제외한 나머지 숫자들이 이미 쓰여있으므로 가운데 빈 칸에는 3이 들어가야 한다.
이와 같이 빈 칸을 차례로 채워 가면 다음과 같은 최종 결과를 얻을 수 있다.
게임 시작 전 스도쿠 판에 쓰여 있는 숫자들의 정보가 주어질 때 모든 빈 칸이 채워진 최종 모습을 출력하는 프로그램을 작성하시오.
풀이
1. 백트래킹을 이용하여 풀 수 있는 문제입니다.
2. 우선 0인 부분만 찾고, 그 부분을 하나씩 들어갈 숫자를 찾는데, 재귀함수를 이용해 진행합니다.
3. 숫자를 찾을 때에는 행, 열, 3x3 박스 안에서 검사하여 찾습니다.
4. 검사하여 들어갈 숫자를 찾으면, 그 다음 0인 부분도 동일하게 찾습니다.
5. 들어갈 숫자가 하나도 없다면, 그 이전에 넣었던 숫자를 다른 숫자로 변경합니다.
전체 코드
board = [list(map(int, input().split())) for _ in range(9)]
zeros = [(i, j) for i in range(9) for j in range(9) if board[i][j] == 0]
def is_promising(i, j):
promising = [1, 2, 3, 4, 5, 6, 7, 8, 9]
# 행열 검사
for k in range(9):
if board[i][k] in promising:
promising.remove(board[i][k])
if board[k][j] in promising:
promising.remove(board[k][j])
i //= 3
j //= 3
for p in range(i * 3, (i + 1) * 3):
for q in range(j * 3, (j + 1) * 3):
if board[p][q] in promising:
promising.remove(board[p][q])
return promising
flag = False
def dfs(x):
global flag
if flag: # 이미 답이 출력된 경우
return
if x == len(zeros):
for row in board:
print(*row)
flag = True
return
else:
(i, j) = zeros[x]
promising = is_promising(i, j)
for num in promising:
board[i][j] = num
dfs(x + 1)
board[i][j] = 0
dfs(0)
'BOJ 백준 알고리즘 > 깊이 우선 탐색 DFS' 카테고리의 다른 글
파이썬 / BOJ 백준 / 14889 스타트와 링크 - 백트래킹 (0) | 2021.09.26 |
---|---|
파이썬 / BOJ 백준 / 14888 연산자 끼워넣기 - 백트래킹 (0) | 2021.09.23 |
파이썬 / BOJ 백준 / 9663 N-Queen - 백트래킹 (2) | 2021.09.10 |
파이썬 / BOJ 백준 / 15652번 N과 M(4) - 백트래킹 (0) | 2021.09.09 |
파이썬 / BOJ 백준 / 15651번 N과 M(3) - 백트래킹 (0) | 2021.09.08 |