티스토리 뷰
문제 출처 : algospot.com :: BOARDCOVER
algospot.com :: BOARDCOVER
게임판 덮기 문제 정보 문제 H*W 크기의 게임판이 있습니다. 게임판은 검은 칸과 흰 칸으로 구성된 격자 모양을 하고 있는데 이 중 모든 흰 칸을 3칸짜리 L자 모양의 블록으로 덮고 싶습니다. 이
algospot.com
1. 내가 생각한 문제 접근 방법
(1) 게임판에 들어가는 블록은 3칸으로 구성되어있다.
- 3개의 변수에 대해 각 칸에 대한 좌표를 저장
- 반복문을 통해 회전 시키고 각 칸에 대응하는 보드판이 비어있으면 블록 설치
- 하지만, 블록을 회전시키는 방법에 대해 고안하지 못했다.
(2) 재귀적 호출을 통해 블록을 설치하고 해체하는 과정을 반복한다.
- 기저 사례를 찾고 기저 사례에서 경우의 수를 반환하여 누적
- 하지만, 재귀 호출을 어떤 방식으로 진행할지 고안하지 못했다.
2. 해설 풀이 방법
(1) 블록이 나올 수 있는 모양을 상대적인 리스트로 표현함
- 이 방법을 통해 블록을 회전시켰을 때, 현재 블록의 위치에서 리스트에 저장된 상대적인 인덱스를 더하고 빼는 과정으로 블록 모양을 지정할 수 있다.
# 블록의 모양을 상대적인 인덱스로 표현
block_type = [[(0, 0), (1, 0), (0, 1)],
[(0, 0), (0, 1), (1, 1)],
[(0, 0), (1, 0), (1, 1)],
[(0, 0), (1, 0), (1, -1)]]
(2) 블록 설치 가능 여부를 반환하는 함수 : setBlock()
- 매개변수 t : 현재 블록의 모양, 반복문을 3번 도는데 각 블록의 칸에 대한 위치를 지정
- 매개변수 delta : 블록을 설치할 지, 제거할 지 결정
- 3개의 칸에 대해 반복문을 통과했다면 블록 설치 가능(True 반환)
- 반복문 도중 블록이 보드판의 범위를 넘어가거나 중복 설치되는 경우(False 반환)
# t : 블럭 모양
# delta : 현재 게임판에 블럭 설치 여부 결정(1 : 설치 / -1 : 제거)
def setBlock(board, r, c, t, delta):
possible = True
for i in range(3):
nr = r + block_type[t][i][0]
nc = c + block_type[t][i][1]
if nr < 0 or nr >= h or nc < 0 or nc >= w:
possible = False
else:
board[nr][nc] += delta
# 값이 1이 넘어갈 경우 블록이 중복되어 설치되어있다고 간주
if board[nr][nc] > 1:
possible = False
return possible
(3) 재귀적 호출을 통해 블록을 설치하는 함수 : cover()
- 블록의 좌상으로부터 우하로 빈 칸을 탐색하여 차례로 블록을 설치
- setBlock()을 통해 블록 설치 여부를 검사하고 설치가 가능한 경우 cover() 함수를 재귀적으로 호출
- 그리고 setBlock()의 delta 인수를 -1로 넘겨 블록 설치를 해제
- 위 과정을 반복하여 최종 누적된 result 값을 반환
def cover(board):
h = len(board)
w = len(board[0])
# 아직 채워지지 않은 가장 위쪽 왼쪽에 있는 칸을 찾음
r, c = -1, -1
for i in range(h):
for j in range(w):
if board[i][j] == 0:
r = i
c = j
break
if r != -1:
break
# 기저 사례 : 모든 칸을 채웠으면 1을 반환
if r == -1:
return 1
result = 0
for t in range(4):
# 게임판을 덮을 수 있는 경우, 재귀 호출을 통해 반복
if setBlock(board, r, c, t, 1):
result += cover(board)
# 설치한 블럭 제거
setBlock(board, r, c, t, -1)
return result
(4) 문제 입-출력
for tc in range(int(input())):
h, w = map(int, input().split())
board = []
for i in range(h):
board.append(list(map(int, input().split())))
print(cover(board))
3. 후기
처음 문제를 봤을 때 '문제를 어떻게 해결해야겠다.' 라는 해결방법은 비교적 쉽게 생각할 수 있었다. 하지만, 막상 이 아이디어를 코드로 구현하려고 하니 쉽게 작성할 수 없었다. 특히, 블록을 회전하는 과정에서 막혔는데 해설에 나와있는 방법은 전혀 떠올리지 못 했다. 개인적으로 블록이 회전할 때 나타나는 패턴에 대해 고민했지만 이를 코드로 구현하려고 했지만 결과적으로 옳은 방법은 아니었다. 재귀 호출을 통한 방법은 아직 몇 문제 풀어보지는 않았지만 쉽게 감이 오지 않는 것이 아쉽게 느껴진다.
LeeSeok-Jun/Algorithmic_Problem_Soving_Strategies
프로그래밍 대회에서 배우는 알고리즘 문제해결 전략. Contribute to LeeSeok-Jun/Algorithmic_Problem_Soving_Strategies development by creating an account on GitHub.
github.com
'프로그래밍 대회에서 배우는 알고리즘 문제해결 전략 > 6장_무식하게 풀기' 카테고리의 다른 글
6.8 문제 : 시계 맞추기(Python) (0) | 2021.03.04 |
---|---|
6.7 예제 : 최적화 문제 - 여행하는 외판원 문제(Python) (0) | 2021.03.04 |
6.3 문제 : 소풍(Python) (0) | 2021.02.25 |
6.2 예제 : 보글 게임(Python) (0) | 2021.02.25 |
공지사항
최근에 올라온 글
최근에 달린 댓글
- Total
- Today
- Yesterday
링크
TAG
- 프로그래밍 대회에서 배우는 알고리즘 문제해결 전략
- 파이썬
- 그리디
- 프로그래밍 대회에서 배우는 알고리즘 문제해결전략
- python
- k번째 답 계산하기
- 난이도:상
- 난이도:하
- 동적 계획법
- 비트 마스크
- 카카오
- 난이도:중
- 마르코프 연쇄
- 프로그래밍 대회에서 배우는 알고리즘 문제 해결 전략
- 종만북
- 프로그래머스
- 구현
- 탐욕법
일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
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 |
글 보관함