문제 설명
고고학자인 "튜브"는 고대 유적지에서 보물과 유적이 가득할 것으로 추정되는 비밀의 문을 발견하였습니다. 그런데 문을 열려고 살펴보니 특이한 형태의 자물쇠로 잠겨 있었고 문 앞에는 특이한 형태의 열쇠와 함께 자물쇠를 푸는 방법에 대해 다음과 같이 설명해 주는 종이가 발견되었습니다.
잠겨있는 자물쇠는 격자 한 칸의 크기가 1 x 1인 N x N 크기의 정사각 격자 형태이고 특이한 모양의 열쇠는 M x M 크기인 정사각 격자 형태로 되어 있습니다.
자물쇠에는 홈이 파여 있고 열쇠 또한 홈과 돌기 부분이 있습니다. 열쇠는 회전과 이동이 가능하며 열쇠의 돌기 부분을 자물쇠의 홈 부분에 딱 맞게 채우면 자물쇠가 열리게 되는 구조입니다. 자물쇠 영역을 벗어난 부분에 있는 열쇠의 홈과 돌기는 자물쇠를 여는 데 영향을 주지 않지만, 자물쇠 영역 내에서는 열쇠의 돌기 부분과 자물쇠의 홈 부분이 정확히 일치해야 하며 열쇠의 돌기와 자물쇠의 돌기가 만나서는 안됩니다. 또한 자물쇠의 모든 홈을 채워 비어있는 곳이 없어야 자물쇠를 열 수 있습니다.
열쇠를 나타내는 2차원 배열 key와 자물쇠를 나타내는 2차원 배열 lock이 매개변수로 주어질 때, 열쇠로 자물쇠를 열수 있으면 true를, 열 수 없으면 false를 return 하도록 solution 함수를 완성해주세요.
from collections import Counter
def solution(key, lock):
answer = False # 잠금 해제 여부를 나타내는 변수
key_cnt = 0 # 열쇠의 돌기 수를 셀 변수
lock_cnt = 0 # 자물쇠의 구멍 수를 셀 변수
lock_zero = [] # 자물쇠의 구멍 위치 저장 리스트
key_one = [] # 열쇠의 돌기 위치 저장 리스트
n = len(lock) # 자물쇠의 크기
m = len(key) # 열쇠의 크기
# 열쇠의 돌기 수와 위치를 구함
for i in range(m):
for j in range(m):
if key[i][j] == 1:
key_cnt += 1
key_one.append([i, j])
# 자물쇠의 구멍 수와 위치를 구함
for i in range(n):
for j in range(n):
if lock[i][j] == 0:
lock_cnt += 1
lock_zero.append([i, j])
# 구멍 수보다 열쇠의 돌기가 부족하면 불가능
if key_cnt < lock_cnt:
return False
# 자물쇠의 구멍 위치를 set으로 변환 (회전한 열쇠와 비교를 쉽게 하기 위함)
lock_zero = set([tuple(i) for i in lock_zero]) # 0도 회전
# 열쇠를 회전시킨 경우들을 생성
key_one1 = [[y, m - 1 - x] for x, y in key_one] # 1회전
key_one2 = [[m - 1 - x, m - 1 - y] for x, y in key_one] # 2회전
key_one3 = [[m - 1 - y, x] for x, y in key_one] # 3회전
l = max(n, m) # 자물쇠와 열쇠의 크기 중 더 큰 값
# 열쇠를 0도 회전한 상태로 자물쇠에 맞추어 보기
for i in range(-(l + 1), l):
for j in range(-(l + 1), l):
result = []
for x, y in key_one:
x1, y1 = x + i, y + j # 열쇠의 돌기를 이동시켜 자물쇠에 맞춰봄
# 자물쇠 영역 안에 있는지 확인
if 0 <= x1 < l and 0 <= y1 < l:
result.append([x1, y1])
result = set([tuple(i) for i in result]) # 결과를 set으로 변환하여 비교
if lock_zero == result: # 자물쇠의 구멍 위치와 일치하면 성공
return True
# 열쇠를 1회전시킨 상태로 자물쇠에 맞추어 보기
for i in range(-(l + 1), l):
for j in range(-(l + 1), l):
result = []
for x, y in key_one1:
x1, y1 = x + i, y + j
if 0 <= x1 < l and 0 <= y1 < l:
result.append([x1, y1])
result = set([tuple(i) for i in result])
if lock_zero == result:
return True
# 열쇠를 2회전시킨 상태로 자물쇠에 맞추어 보기
for i in range(-(l + 1), l):
for j in range(-(l + 1), l):
result = []
for x, y in key_one2:
x1, y1 = x + i, y + j
if 0 <= x1 < l and 0 <= y1 < l:
result.append([x1, y1])
result = set([tuple(i) for i in result])
if lock_zero == result:
return True
# 열쇠를 3회전시킨 상태로 자물쇠에 맞추어 보기
for i in range(-(l + 1), l):
for j in range(-(l + 1), l):
result = []
for x, y in key_one3:
x1, y1 = x + i, y + j
if 0 <= x1 < l and 0 <= y1 < l:
result.append([x1, y1])
result = set([tuple(i) for i in result])
if lock_zero == result:
return True
return answer # 위 조건들을 모두 만족하지 않으면 False 반환
'코딩 테스트' 카테고리의 다른 글
코딩 테스트(Python) 2022 KAKAO BLIND RECRUITMENT파괴되지 않은 건물 (0) | 2025.01.28 |
---|---|
코딩 테스트(Python) 2021 KAKAO BLIND RECRUITMENT 합승 택시 요금 (1) | 2025.01.22 |
코딩 테스트(Python) 순위 (0) | 2024.12.20 |
코딩 테스트(Python) 풍선 터트리기 (0) | 2024.12.20 |
코딩 테스트(Python) 거스름돈 (1) | 2024.12.20 |