반응형
250x250
Notice
Recent Posts
Recent Comments
Link
«   2025/06   »
1 2 3 4 5 6 7
8 9 10 11 12 13 14
15 16 17 18 19 20 21
22 23 24 25 26 27 28
29 30
Tags more
Archives
Today
Total
관리 메뉴

멋진 개발자가 되고 싶다

[백준/Python] 2580.스도쿠(feat.DFS) 본문

Algorithm Study/백준

[백준/Python] 2580.스도쿠(feat.DFS)

오패산개구리 2021. 7. 31. 16:44
728x90
반응형

문제

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

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

  1. 각각의 가로줄과 세로줄에는 1부터 9까지의 숫자가 한 번씩만 나타나야 한다.
  2. 굵은 선으로 구분되어 있는 3x3 정사각형 안에도 1부터 9까지의 숫자가 한 번씩만 나타나야 한다.

위의 예의 경우, 첫째 줄에는 1을 제외한 나머지 2부터 9까지의 숫자들이 이미 나타나 있으므로 첫째 줄 빈칸에는 1이 들어가야 한다.

또한 위쪽 가운데 위치한 3x3 정사각형의 경우에는 3을 제외한 나머지 숫자들이 이미 쓰여있으므로 가운데 빈 칸에는 3이 들어가야 한다.

이와 같이 빈 칸을 차례로 채워 가면 다음과 같은 최종 결과를 얻을 수 있다.

게임 시작 전 스도쿠 판에 쓰여 있는 숫자들의 정보가 주어질 때 모든 빈 칸이 채워진 최종 모습을 출력하는 프로그램을 작성하시오.

입력

아홉 줄에 걸쳐 한 줄에 9개씩 게임 시작 전 스도쿠판 각 줄에 쓰여 있는 숫자가 한 칸씩 띄워서 차례로 주어진다. 스도쿠 판의 빈 칸의 경우에는 0이 주어진다. 스도쿠 판을 규칙대로 채울 수 없는 경우의 입력은 주어지지 않는다.

출력

모든 빈 칸이 채워진 스도쿠 판의 최종 모습을 아홉 줄에 걸쳐 한 줄에 9개씩 한 칸씩 띄워서 출력한다.

스도쿠 판을 채우는 방법이 여럿인 경우는 그 중 하나만을 출력한다.

 

 

 

 

**** 나의 코드 ****

 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
import sys
 
board = []
cnt = 0  # 빈칸의 개수
found = False  # 0을 모두 채웠는지 여부
for _ in range(9):
    board.append(list(sys.stdin.readline().split()))
 
# 빈칸의 위치 저장
blanks = []
for i in range(9):
    for j in range(9):
        if board[i][j] == '0':
            blanks.append((i, j))
            cnt += 1
 
 
# 빈칸에 들어간 숫자가 적절한지
def check(x, y, i):
    for p in range(9):
        # 행 체크
        if board[x][p] == i and p != y:
            return False
        # 열 체크
        if board[p][y] == i and p != x:
            return False
    # 3x3 체크
    square_x = 3 * (x // 3)
    square_y = 3 * (y // 3)
    for a in range(square_x, square_x + 3):
        for b in range(square_y, square_y + 3):
            if board[a][b] == i:
                if a != x and b != y:
                    return False
    return True
 
 
def dfs(N):
    global found
    if N == cnt:  # 모든 빈칸을 채웠다면
        for i in range(9):
            print(*board[i])
        found = True
        return
    else:
        # 빈칸에 하나씩 숫자 넣기
        x, y = blanks[N][0], blanks[N][1]
        for i in range(110):
            board[x][y] = str(i)
            if check(x, y, str(i)):
                dfs(N + 1)
            if found:
                return
        board[x][y] = 0
        return
 
 
dfs(0)
 
cs

 

 

해설:

 

코드 자체에 대한 해설은 주석을 참고하면 된다.

 

처음 알고리즘을 고려할때는 행, 열, 3x3 순으로 빈칸이 하나만 있으면 채워가는 식으로 하면 될 거라 생각했음.

 

하지만 빈칸이 모두 두 개 이상으로 이루어진 테스트 케이스도 있어서 이 알고리즘은 실패..

 

다음 알고리즘은 위와 같이 고려하였다.

 

1. 빈칸을 모두 찾아서 좌표를 저장

 

2. 빈칸마다 1~9를 하나씩 넣어 올바른지 확인(check 함수 참고)해보고

올바르면 그 값을 넣고 올바르지 않으면 다시 빈칸으로 놔둠

(다른 재귀들도 써야되니까)

 

3. 

 

모든 빈칸을 채워줬으면 출력 후 종료

728x90
반응형