스도쿠는 18세기 스위스 수학자가 만든 '라틴 사각형'이랑 퍼즐에서 유래한 것으로 현재 많은 인기를 누리고 있다. 이 게임은 아래 그림과 같이 가로, 세로 각각 9개씩 총 81개의 작은 칸으로 이루어진 정사각형 판 위에서 이뤄지는데, 게임 시작 전 일부 칸에는 1부터 9까지의 숫자 중 하나가 쓰여 있다.
나머지 빈 칸을 채우는 방식은 다음과 같다.
- 각각의 가로줄과 세로줄에는 1부터 9까지의 숫자가 한 번씩만 나타나야 한다.
- 굵은 선으로 구분되어 있는 3x3 정사각형 안에도 1부터 9까지의 숫자가 한 번씩만 나타나야 한다.
위의 예의 경우, 첫째 줄에는 1을 제외한 나머지 2부터 9까지의 숫자들이 이미 나타나 있으므로 첫째 줄 빈칸에는 1이 들어가야 한다.
또한 위쪽 가운데 위치한 3x3 정사각형의 경우에는 3을 제외한 나머지 숫자들이 이미 쓰여있으므로 가운데 빈 칸에는 3이 들어가야 한다.
이와 같이 빈 칸을 차례로 채워 가면 다음과 같은 최종 결과를 얻을 수 있다.
게임 시작 전 스도쿠 판에 쓰여 있는 숫자들의 정보가 주어질 때 모든 빈 칸이 채워진 최종 모습을 출력하는 프로그램을 작성하시오.
입력
아홉 줄에 걸쳐 한 줄에 9개씩 게임 시작 전 스도쿠판 각 줄에 쓰여 있는 숫자가 한 칸씩 띄워서 차례로 주어진다. 스도쿠 판의 빈 칸의 경우에는 0이 주어진다. 스도쿠 판을 규칙대로 채울 수 없는 경우의 입력은 주어지지 않는다.
출력
모든 빈 칸이 채워진 스도쿠 판의 최종 모습을 아홉 줄에 걸쳐 한 줄에 9개씩 한 칸씩 띄워서 출력한다.
스도쿠 판을 채우는 방법이 여럿인 경우는 그 중 하나만을 출력한다.
풀이
0이 적힌 칸의 좌표를 q라는 리스트에 저장하고 리스트의 앞에서부터 탐색했다.
탐색한 좌표를 기준으로 열과 행, 좌표가 포함된 곳의 3x3 칸을 비교해 1~9 중 칸에 들어올 수 있는 숫자를 찾았고, 숫자를 하나 선택한 뒤 q 리스트의 다음 좌표에 어떤 숫자가 들어갈 수 있는지 탐색했다.
q리스트에 있는 모든 좌표에 숫자가 채워지면 그 때 완성된 스도쿠를 print 했다.
처음에는 q 리스트에 좌표를 뺐다가 다시 0번 index에 집어넣어 탐색을 하려 했다.
하지만 그 과정에서 시간이 오래 걸려 rear라는 변수를 이용해 현재 탐색하고 있는 q리스트의 index를 가리키도록 했다.
만약 탐색결과 들어갈 수 있는 수가 없으면 이전 좌표에 넣은 숫자를 바꿔야 하므로 다시 되돌아가 다른 숫자를 넣고 다시 다음 좌표에 들어갈 숫자를 탐색하도록 했다.
Code
import sys
input=sys.stdin.readline
def sudoku(y,x):
cnt=[0]*10
num=[]
for i in range(9): # 행 숫자 탐색
cnt[lst[y][i]]=1
for i in range(9): # 열 숫자 탐색
cnt[lst[i][x]]=1
a=y//3
b=x//3
for i in range(3): # 3X3 숫자 탐색
for j in range(3):
cnt[lst[3*a+i][3*b+j]]=1
for i in range(1,10):
if cnt[i]==0: # 들어갈 수 있는 숫자를 list형태로 반환
num.append(i)
return num
def func(rear,k): # rear => q의 몇번째 index인지
global ans
global flag
if flag:
return
if rear<k:
y,x=q[rear]
s_l=sudoku(y,x)
for i in s_l:
lst[y][x]=i
func(rear+1,k)
lst[y][x]=0
else:
if not flag: # 만약 스도쿠가 완성 됐다면 출력
for i in lst:
print(*i)
flag=True
return True
flag=False
ans=[[0]*9 for _ in range(9)]
lst=[list(map(int,input().split())) for _ in range(9)]
q=[]
for y in range(9): # 0 이 있는 좌표를 q에 저장
for x in range(9):
if lst[y][x]==0:
q.append((y,x))
k=len(q)
func(0,k)
python3로는 시간초과가 나와 pypy로 풀었다.
좌표에 들어갈 수 있는 숫자를 백트래킹 후 다시 탐색하는 과정에서 시간이 오래 걸리는 것 같다. 이를 해결하려면 처음에 칸에 들어 갈 수 있는 숫자들을 전부 저장한 뒤 풀어야 할 것 같다.
'Algorithm > BAEKJOON' 카테고리의 다른 글
[백준/Python] 10844번 - 쉬운 계단 수 (1) | 2024.01.03 |
---|---|
[백준/Python] 1463 - 1로 만들기 (1) | 2024.01.03 |
[백준/Python] 9663번 - N-Queen (1) | 2024.01.03 |
[백준/Python] 2304번 - 창고 다각형 (1) | 2024.01.03 |
[백준/Python] 2116번 - 주사위 쌓기 (1) | 2024.01.03 |