스도쿠는 18세기 스위스 수학자가 만든 '라틴 사각형'이랑 퍼즐에서 유래한 것으로 현재 많은 인기를 누리고 있다. 이 게임은 아래 그림과 같이 가로, 세로 각각 9개씩 총 81개의 작은 칸으로 이루어진 정사각형 판 위에서 이뤄지는데, 게임 시작 전 일부 칸에는 1부터 9까지의 숫자 중 하나가 쓰여 있다.
나머지 빈 칸을 채우는 방식은 다음과 같다.
각각의 가로줄과 세로줄에는 1부터 9까지의 숫자가 한 번씩만 나타나야 한다.
굵은 선으로 구분되어 있는 3x3 정사각형 안에도 1부터 9까지의 숫자가 한 번씩만 나타나야 한다.
위의 예의 경우, 첫째 줄에는 1을 제외한 나머지 2부터 9까지의 숫자들이 이미 나타나 있으므로 첫째 줄 빈칸에는 1이 들어가야 한다.
또한 위쪽 가운데 위치한 3x3 정사각형의 경우에는 3을 제외한 나머지 숫자들이 이미 쓰여있으므로 가운데 빈 칸에는 3이 들어가야 한다.
이와 같이 빈 칸을 차례로 채워 가면 다음과 같은 최종 결과를 얻을 수 있다.
게임 시작 전 스도쿠 판에 쓰여 있는 숫자들의 정보가 주어질 때 모든 빈 칸이 채워진 최종 모습을 출력하는 프로그램을 작성하시오.
입력
아홉 줄에 걸쳐 한 줄에 9개씩 게임 시작 전 스도쿠판 각 줄에 쓰여 있는 숫자가 한 칸씩 띄워서 차례로 주어진다. 스도쿠 판의 빈 칸의 경우에는 0이 주어진다. 스도쿠 판을 규칙대로 채울 수 없는 경우의 입력은 주어지지 않는다.
출력
모든 빈 칸이 채워진 스도쿠 판의 최종 모습을 아홉 줄에 걸쳐 한 줄에 9개씩 한 칸씩 띄워서 출력한다.
스도쿠 판을 채우는 방법이 여럿인 경우는 그 중 하나만을 출력한다.
제한
baekjoon의 백트래킹 알고리즘으로 풀 수 있는 입력만 주어진다. 다음은 그 알고리즘의 수행 시간이다.
C++14: 80ms
Java: 292ms
PyPy3: 1172ms
예제 입력 1 복사
0 3 5 4 6 9 2 7 8
7 8 2 1 0 5 6 0 9
0 6 0 2 7 8 1 3 5
3 2 1 0 4 6 8 9 7
8 0 4 9 1 3 5 0 6
5 9 6 8 2 0 4 1 3
9 1 7 6 5 2 0 8 0
6 0 3 7 0 1 9 5 2
2 5 8 3 9 4 7 6 0
예제 출력 1 복사
1 3 5 4 6 9 2 7 8
7 8 2 1 3 5 6 4 9
4 6 9 2 7 8 1 3 5
3 2 1 5 4 6 8 9 7
8 7 4 9 1 3 5 2 6
5 9 6 8 2 7 4 1 3
9 1 7 6 5 2 3 8 4
6 4 3 7 8 1 9 5 2
2 5 8 3 9 4 7 6 1
시도1
3*3
검사해도 ㄱㅊ?시도2
-> 83%로 파이썬에선 시간 초과
import sys
def sdk(z,num,chk):
candi=[]
chk=[0]*10
if num==len(zero):
for i in range(9):
for j in range(9):
print(arr[i][j],end=" ")
print()
sys.exit()
else:
for k in range(9):#arr은 0~8 (9개)
chk[arr[k][z[num][1]]]=1 #행 체크 - 행에서 아직 나오지 않은 숫자 collect
chk[arr[z[num][0]][k]]=1 #열 체크
#####################################
#3*3 검사방법 추가
xr= (z[num][0])
xc= (z[num][1])
dx = (xr//3)*3
dy = (xc//3)*3
for i in range(dx,dx+3):
for j in range(dy,dy+3):
chk[arr[i][j]]=1
#######################################
for m in range(1,10):
if chk[m]==0: # 빈 칸에 들어갈 값 후보들
candi.append(m)
for i in candi:
arr[z[num][0]][z[num][1]]=i
sdk(z,num+1,chk)
arr[z[num][0]][z[num][1]]=0
if __name__=="__main__":
zero=[]
global arr
chk=[0]*10#1~9
arr=[list(map(int,sys.stdin.readline().split())) for i in range(9)]
for i in range(9):
for j in range(9):
if arr[i][j]==0:
zero.append((i,j))#0이 행, 1이 열
sdk(zero,0,chk)
3*3
순으로 둘러볼 예정이었는데 어케 구현할 지 넘 복잡def row(i,j,chk):
global arr
for k in range(10):#1~9
chk[arr[k][j]]=1 #행 검사 - 행에서 아직 나오지 않은 숫자 collect
for h in range(1,10):
if chk[h]==0:#h는 후보가 되는 아이 (행에 들어갈)
arr[i][j]=h#h를 현재 arr의 빈칸에 넣어보고 검사하기
chk[h]=1#h체크
if col(i,j,h):
arr[i][j]=h
return
chk[h]=0
arr[i][j]=0
def col(i,j,h):
for k in range(10):
if arr[i][k]==h:
return False
#모두 chk되지 않은 상황이면 또 검사해서 열 채워주기
for h in range(1,10):#그리고 혹시 열에 안채워진애 있나 점검
if chk[h]==0:#h는 후보가 되는 아이 (텅 빈 열에 들어갈)
if __name__=="__main__":
global arr
arr=[0]*9
chk=[0]*10
for i in range(9):
arr[i]=list(map(int,input().split()))
for i in range(9):
for j in range(9):
if arr[i][j]==0:
row(i,j,chk)#i,j는 우리가 메꿔야 할 아이의 행과 열
-> chkcol, chkrow를 나누지 말고 합쳐서가야한다!
==> 행 체크하고 열 넘기는게 아니고
행 체크 , 열 체크 하자
약간 아래 코드 느낌으로...
def row(i,j,chk):
global arr
for k in range(10):#1~9
chk[arr[k][j]]=1 #행 검사 - 행에서 아직 나오지 않은 숫자 collect
for l in range(10):
chk[arr[i][l]]=1
for m in range(1,10):
if chk[m]==0:
arr[i][j]=m
=> 위에 방향에서 빵꾸 뚫린 애들만 경우의 수 알고 싶기 때문에 그 애들을 모아주는 과정이 필요
def sdk(z):
global arr
for i in range(len(z)):
for k in range(9):#arr은 0~8 (9개)
chk[arr[k][z[i][1]]]=1 #행 검사 - 행에서 아직 나오지 않은 숫자 collect
chk[arr[z[i][0]][k]]=1 #열 검사
for m in range(1,10):
if chk[m]==0: # 빈 칸에 들어갈 값 후보들
candi.append(chk[m])
if __name__=="__main__":
candi=[]
zero=[]
global arr
arr=[0]*9
chk=[0]*10#1~9
for i in range(9):
arr[i]=list(map(int,input().split()))
for i in range(9):
for j in range(9):
if arr[i][j]==0:
#0이 행, 1이 열
zero.append((i,j))
sdk(zero)
=> 위와 같이 진행 : 빵꾸뚫린 애에 들어갈 수 있는 애 (chk에 1되지 않은 애) 선별해두었음
def sdk(z,num):
global arr
if num==len(z):
return True
else :
for k in range(9):#arr은 0~8 (9개)
chk[arr[k][z[num][1]]]=1 #행 검사 - 행에서 아직 나오지 않은 숫자 collect
chk[arr[z[num][0]][k]]=1 #열 검사
for m in range(1,10):
if chk[m]==0: # 빈 칸에 들어갈 값 후보들
candi.append(chk[m])
if len(candi)==0:
return False
else :
for i in candi:
arr[z[num][0]][z[num][1]]=i
chk=[]
sdk(z,num+1)
arr[z[num][0]][z[num][1]]=0
if __name__=="__main__":
candi=[]
zero=[]
arr=[0]*9
for i in range(9):
arr[i]=list(map(int,input().split()))
for i in range(9):
for j in range(9):
if arr[i][j]==0:
#0이 행, 1이 열
zero.append((i,j))
chk=[0]*10#1~9
sdk(zero,0)#zero의 0번째 인덱스부터 검사하긔
print("________________________")
for i in range(9):
for j in range(9):
print(arr[i][j], end=" ")
print()
=> num이 zero(빵꾸난애들 모아둔 리스트) 길이랑 the same해지면 stop하도록
=> 근데 return 했는데 조건에 부합했는데도 스탑하지 않는다..why..??(아래 코드)
def sdk(z,num,chk):
global arr
print(num)
print(len(z))
if num==len(z):
print("stop")
return arr
else:
for k in range(9):#arr은 0~8 (9개)
chk[arr[k][z[num][1]]]=1 #행 검사 - 행에서 아직 나오지 않은 숫자 collect
chk[arr[z[num][0]][k]]=1 #열 검사
for m in range(1,10):
if chk[m]==0: # 빈 칸에 들어갈 값 후보들
candi.append(chk[m])
if len(candi)==0:
return False
else :
for i in candi:
arr[z[num][0]][z[num][1]]=i
chk=[0]*10
chk[i]=1
sdk(z,num+1,chk)
arr[z[num][0]][z[num][1]]=0
if __name__=="__main__":
candi=[]
zero=[]
global arr
arr=[0]*9
chk=[0]*10#1~9
for i in range(9):
arr[i]=list(map(int,input().split()))
for i in range(9):
for j in range(9):
if arr[i][j]==0:
zero.append((i,j))#0이 행, 1이 열
full=sdk(zero,0,chk)
for i in range(9):
for j in range(9):
print(full[i][j])
return 썼는 데도 계속 반복됐던 원인 ..
내가 full=sdk로 해놓고 쟤를 계속 print하게 해서..^^
원인
full=sdk(zero,0,chk)
for i in range(9):
for j in range(9):
print(full[i][j])
나름 수정+보완을 했는데 재귀가 끝나도 arr이 전혀 번하지가 않는드앙
def sdk(z,num,chk):
candi=[]
if num==len(z):
return arr
else:
for k in range(9):#arr은 0~8 (9개)
chk[arr[k][z[num][1]]]=1 #행 검사 - 행에서 아직 나오지 않은 숫자 collect
chk[arr[z[num][0]][k]]=1 #열 검사
for m in range(1,10):
if chk[m]==0: # 빈 칸에 들어갈 값 후보들
candi.append(m)
if len(candi)==0:
return False
else :
for i in candi:
arr[z[num][0]][z[num][1]]=i
chk=[0]*10
chk[i]=1
sdk(z,num+1,chk)
arr[z[num][0]][z[num][1]]=0
chk=[0]*10
if __name__=="__main__":
zero=[]
global arr
arr=[0]*9
chk=[0]*10#1~9
for i in range(9):
arr[i]=list(map(int,input().split()))
for i in range(9):
for j in range(9):
if arr[i][j]==0:
zero.append((i,j))#0이 행, 1이 열
sdk(zero,0,chk)
print("_______________________________________")
for i in range(9):
for j in range(9):
print(arr[i][j],end=" ")
print()
=> 출력해서 살펴보니
요만큼까지만 진행된당 호엥~~~밑에 빵꾸들은 안채워짐
=> 왜냐하면 내가 재귀를 candi가 존재할 때로 한정해놨거등...^^
=> candi가 0이 되면 더 이상 재귀 안돌아..ㅎㅎ;;;
--> 그렇다 답은 chk가 적절히 초기화되지 않고 있었다는 것..흑흑
def sdk(z,num,chk):
candi=[]
chk=[0]*10
if num==len(zero):
print("--------------------------------")
for i in range(9):
for j in range(9):
print(arr[i][j],end=" ")
print()
print("--------------------------------")
return
else:
for k in range(9):#arr은 0~8 (9개)
chk[arr[k][z[num][1]]]=1 #행 검사 - 행에서 아직 나오지 않은 숫자 collect
chk[arr[z[num][0]][k]]=1 #열 검사
for m in range(1,10):
if chk[m]==0: # 빈 칸에 들어갈 값 후보들
candi.append(m)
if len(candi):
for i in candi:
arr[z[num][0]][z[num][1]]=i
sdk(z,num+1,chk)
arr[z[num][0]][z[num][1]]=0
else :
sdk(z,num+1,chk)
if __name__=="__main__":
zero=[]
global arr
arr=[0]*9
chk=[0]*10#1~9
for i in range(9):
arr[i]=list(map(int,input().split()))
for i in range(9):
for j in range(9):
if arr[i][j]==0:
zero.append((i,j))#0이 행, 1이 열
sdk(zero,0,chk)
-> 결과
def sdk(z,num,chk):
candi=[]
chk=[0]*10
if num==len(zero):
for i in range(9):
for j in range(9):
print(arr[i][j],end=" ")
print()
exit
else:
for k in range(9):#arr은 0~8 (9개)
chk[arr[k][z[num][1]]]=1 #행 검사 - 행에서 아직 나오지 않은 숫자 collect
chk[arr[z[num][0]][k]]=1 #열 검사
for m in range(1,10):
if chk[m]==0: # 빈 칸에 들어갈 값 후보들
candi.append(m)
if len(candi):
for i in candi:
arr[z[num][0]][z[num][1]]=i
sdk(z,num+1,chk)
arr[z[num][0]][z[num][1]]=0
else :
sdk(z,num+1,chk)
if __name__=="__main__":
zero=[]
global arr
arr=[0]*9
chk=[0]*10#1~9
for i in range(9):
arr[i]=list(map(int,input().split()))
for i in range(9):
for j in range(9):
if arr[i][j]==0:
zero.append((i,j))#0이 행, 1이 열
sdk(zero,0,chk)
import sys
def sdk(z,num,chk):
candi=[]
chk=[0]*10
if num==len(zero):
for i in range(9):
for j in range(9):
print(arr[i][j],end=" ")
print()
sys.exit()
else:
for k in range(9):#arr은 0~8 (9개)
chk[arr[k][z[num][1]]]=1 #행 체크 - 행에서 아직 나오지 않은 숫자 collect
chk[arr[z[num][0]][k]]=1 #열 체크
for m in range(1,10):
if chk[m]==0: # 빈 칸에 들어갈 값 후보들
candi.append(m)
if len(candi):
for i in candi:
arr[z[num][0]][z[num][1]]=i
sdk(z,num+1,chk)
arr[z[num][0]][z[num][1]]=0
else :
sdk(z,num+1,chk)
if __name__=="__main__":
zero=[]
global arr
chk=[0]*10#1~9
arr=[list(map(int,sys.stdin.readline().split())) for i in range(9)]
for i in range(9):
for j in range(9):
if arr[i][j]==0:
zero.append((i,j))#0이 행, 1이 열
sdk(zero,0,chk)
3*3
박스 검사 안함;)=> 근데 1%만에 틀림...........흑흑 why....?
=> row랑 column만 검사하고 내 주변 8개 검사는 안했기 때문이라고 추정
https://hwiyong.tistory.com/305 이 분의 3*3
검사 방법을 참조해 추가하겠습니당
x = zeros[index][0]
y = zeros[index][1]
dx = (x//3) * 3
dy = (y//3) * 3
________________________________________
# 3*3 box 검사
for i in range(dx, dx + 3):
for j in range(dy, dy + 3):
check_num = sdk[i][j]
if(check_num):
num_list[check_num] = False
import sys
def sdk(z,num,chk):
candi=[]
chk=[0]*10
if num==len(zero):
for i in range(9):
for j in range(9):
print(arr[i][j],end=" ")
print()
sys.exit()
else:
for k in range(9):#arr은 0~8 (9개)
chk[arr[k][z[num][1]]]=1 #행 체크 - 행에서 아직 나오지 않은 숫자 collect
chk[arr[z[num][0]][k]]=1 #열 체크
#####################################
#3*3 검사방법 추가
xr= (z[num][0])
xc= (z[num][1])
dx = (xr//3)*3
dy = (xc//3)*3
for i in range(dx,dx+3):
for j in range(dy,dy+3):
chk[arr[i][j]]=1
#######################################
for m in range(1,10):
if chk[m]==0: # 빈 칸에 들어갈 값 후보들
candi.append(m)
if len(candi):
for i in candi:
arr[z[num][0]][z[num][1]]=i
sdk(z,num+1,chk)
arr[z[num][0]][z[num][1]]=0
else :
sdk(z,num+1,chk)
if __name__=="__main__":
zero=[]
global arr
chk=[0]*10#1~9
arr=[list(map(int,sys.stdin.readline().split())) for i in range(9)]
for i in range(9):
for j in range(9):
if arr[i][j]==0:
zero.append((i,j))#0이 행, 1이 열
sdk(zero,0,chk)
- 이차원 배열 입력 및 탐색 방법 with sys
sdk = [list(map(int, input().split())) for _ in range(9)] zeros = [(i, j) for i in range(9) for j in range(9) if sdk[i][j] == 0]
3*3
찾기def checkRect(x, y, a): nx = x // 3 * 3 ny = y // 3 * 3 for i in range(3): for j in range(3): if a == graph[nx+i][ny+j]: return False return True