본문 바로가기
Algorithm/BAEKJOON

[백준/Python] 2580번 - 스도쿠

by code_pie 2024. 1. 3.

 

 

스도쿠는 18세기 스위스 수학자가 만든 '라틴 사각형'이랑 퍼즐에서 유래한 것으로 현재 많은 인기를 누리고 있다. 이 게임은 아래 그림과 같이 가로, 세로 각각 9개씩 총 81개의 작은 칸으로 이루어진 정사각형 판 위에서 이뤄지는데, 게임 시작 전 일부 칸에는 1부터 9까지의 숫자 중 하나가 쓰여 있다.

 
 

나머지 빈 칸을 채우는 방식은 다음과 같다.

  1. 각각의 가로줄과 세로줄에는 1부터 9까지의 숫자가 한 번씩만 나타나야 한다.
  2. 굵은 선으로 구분되어 있는 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로 풀었다.

 

좌표에 들어갈 수 있는 숫자를 백트래킹 후 다시 탐색하는 과정에서 시간이 오래 걸리는 것 같다. 이를 해결하려면 처음에 칸에 들어 갈 수 있는 숫자들을 전부 저장한 뒤 풀어야 할 것 같다.

 

 

 

2580번: 스도쿠

스도쿠는 18세기 스위스 수학자가 만든 '라틴 사각형'이랑 퍼즐에서 유래한 것으로 현재 많은 인기를 누리고 있다. 이 게임은 아래 그림과 같이 가로, 세로 각각 9개씩 총 81개의 작은 칸으로 이루

www.acmicpc.net

 

반응형