출처: 프로그래머스 코딩 테스트 연습, https://programmers.co.kr/learn/challenges
이 문제는 문제의 효율성 고려나 어려운 개념을 요구하는 게 아니라
주어진 복잡한 instructions을 코드로 구현 할 수 있는 지를 묻는 문제입니다.
따라서 전체과정을 도식화하는 능력과 깔끔한 코드를 짜는게 핵심이라고 생각합니다.
핵심 개념:
TIP:
첫 번째, 적당한 Matrix rotation를 이용해서 문제에서 주어지는 Matrix의 좌표를
우리가 평소에 사용하는 Matrix의 좌표로 바꾸어 놓고, 문제를 생각하면 좀 더 수월합니다.
몇 가지의 경우를 종이에 적어보시면, 어떻게 치환 할 지 패턴이 보이실 겁니다.
Ex) n = 5일떄, (0,0) -> (5,0), (0,3) -> (2, 0), (3,4) -> (1, 3)
※ 앞: 문제에서 주어진 좌표, 뒤: 우리가 실제 사용할 좌표
두 번째, Bit maninpuation을 이용하면, 설치, 삭제 또는 현재 상태까지 나타낼 수 있습니다.
OR: 설치, XOR: 삭제, xxxx: 앞에 두 개의 digit은 기둥의 상태, 뒤에 두 개의 digits은 보의 상태
1: 있다 0: 없다로 생각하고 아래와 같이 생각하면 편합니다.
Ex) 0000: 아무것도 없다, 1000: 기둥 아랫부분만 있다. ,1100: 기둥 아랫부분 과 기둥 윗부분이 있다.
1011: 기둥 아랫부분 과 보의 왼쪽과 보의 오른쪽이 있다., 0001: 보의 오른쪽만 있다.
마지막으로, 이 문제는, 설치보단 삭제 부분이 조금 까다롭습니다.
혹시 테스트가 13번 이후로 다 틀린다면, 삭제 부분에서 문제가 있을 확률이 큽니다.
풀이법
저 같은 경우 이걸 아래와 같은 과정을 도식화하여 풀었습니다.
워낙 코드가 길어, 제 코드 리딩은 도움이 안될 거 같습니다.
- 삭제할 좌표에 실제로 보 또는 기둥이 존재하는 지 판단 (없을시 return)
- 일단 삭제한다고 가정
- 영향을 끼칠 좌표들의 유효성 검사
- 영향을 끼칠 좌표들이 모두 유효하다면 삭제 그대로 진행
- 하나라도 유효하지 않으면, 다시 삭제했던 구조물 재설치
구현 by Python
import os
import sys
def pillar_alive(coord, matrix):
x, y = coord
pillar_start, pillar_end, bar_start, bar_end = Checker(matrix[x][y])
if pillar_end or bar_start or bar_end: return True
else: return False
def bar_alive(coord, matrix, ttype):
x, y = coord
C_pillar_start, C_pillar_end, C_bar_start, C_bar_end = Checker(matrix[x][y])
if ttype == 'left':
L_pillar_start, L_pillar_end, L_bar_start, L_bar_end = Checker(matrix[x][y-1])
if C_pillar_end or L_pillar_end: return True
elif C_bar_start and L_bar_end: return True
else: return False
elif ttype == 'right': # given is start
R_pillar_start, R_pillar_end, R_bar_start, R_bar_end = Checker(matrix[x][y+1])
if C_pillar_end or R_pillar_end: return True
elif C_bar_end and R_bar_start: return True
else: return False
else:
print('IMPOSSIBLE')
def Checker(value) -> list:
#result = [pillar's start, pillar's end, bar's start, bar's end]
_bit = '{:04b}'.format(value)
result = []
for _ in _bit:
if _ == '0': result.append(False)
elif _ == '1': result.append(True)
else: print("Impossible: ", _)
return result
def CoordSwapper1(coord, matrix): # problemSetting coord -> build_it coord
x, y = coord
swapped_x = len(matrix) - 1 - y
swapped_y = x
return (swapped_x, swapped_y)
def CoordSwapper2(coord, matrix): # built_in coord -> problemSetting coord
x, y = coord
swapped_x = y
swapped_y = len(matrix) - 1 - x
return (swapped_x, swapped_y)
def remove_bar(coord, matrix):
x, y = coord
L_pillar_start, L_pillar_end, L_bar_start, L_bar_end = Checker(matrix[x][y])
R_pillar_start, R_pillar_end, R_bar_start, R_bar_end = Checker(matrix[x][y+1])
if not L_bar_start: return
#remove
matrix[x][y]^= 2; matrix[x][y+1]^= 1
L_pillar_TEST = True if (not L_pillar_start) or pillar_alive((x,y), matrix) else False
R_pillar_TEST = True if (not R_pillar_start) or pillar_alive((x, y+1), matrix) else False
L_bar_TEST = True if (not L_bar_end) or bar_alive((x, y), matrix, 'left') else False
R_bar_TEST = True if (not R_bar_start) or bar_alive((x, y+1), matrix, 'right') else False
if L_pillar_TEST and R_pillar_TEST and L_bar_TEST and R_bar_TEST: return
else: matrix[x][y]|= 2; matrix[x][y+1]|= 1 #reinstall
def remove_pillar(coord, matrix):
x, y = coord
D_pillar_start, D_pillar_end, D_bar_start, D_bar_end = Checker(matrix[x][y])
U_pillar_start, U_pillar_end, U_bar_start, U_bar_end = Checker(matrix[x-1][y])
if not D_pillar_start: return
#remove
matrix[x][y]^= 8; matrix[x-1][y]^= 4
U_pillar_TEST = True if (not U_pillar_start) or pillar_alive((x-1, y), matrix) else False
L_bar_TEST = True if (not U_bar_end) or bar_alive((x-1, y), matrix, 'left') else False
R_bar_TEST = True if (not U_bar_start) or bar_alive((x-1, y), matrix, 'right') else False
if U_pillar_TEST and L_bar_TEST and R_bar_TEST: return
else: matrix[x][y]|= 8; matrix[x-1][y]|= 4 # reinstall
def install_pillar(coord, matrix):
x, y = coord
pillar_start, pillar_end, bar_start, bar_end = Checker(matrix[x][y])
if x == len(matrix)-1 or bar_start or bar_end or pillar_end:
matrix[x][y] |= 8
matrix[x-1][y] |= 4
def install_bar(coord, matrix):
x, y = coord
L_pillar_start, L_pillar_end, L_bar_start, L_bar_end = Checker(matrix[x][y])
R_pillar_start, R_pillar_end, R_bar_start, R_bar_end = Checker(matrix[x][y+1])
if L_pillar_end or R_pillar_end or (L_bar_end and R_bar_start):
matrix[x][y] |= 2
matrix[x][y+1] |= 1
def show_all(matrix, res):
n = len(matrix)
for x in range(n):
for y in range(n):
pillar_start, pillar_end, bar_start, bar_end = Checker(matrix[x][y])
_x, _y = CoordSwapper2( (x, y), matrix)
if pillar_start: res.append([_x,_y,0])
if bar_start: res.append([_x,_y,1])
return
def solution(n, build_frame):
res = []; matrix = [[0]*(n+1) for i in range(n+1)]
for op in build_frame:
x, y, a, b = op
_x, _y = CoordSwapper1((x,y), matrix)
if a == 0 and b == 0: remove_pillar((_x,_y), matrix)
elif a == 0 and b == 1: install_pillar((_x,_y), matrix)
elif a == 1 and b == 0: remove_bar((_x,_y), matrix)
elif a == 1 and b == 1: install_bar((_x,_y), matrix)
else: print("IMPOSSIBLE: ", op)
show_all(matrix, res)
res.sort()
return res