GitHub - Seungkyu-Han/PS_strategy: 알고리즘 분류하는 워크플레이스
알고리즘 분류하는 워크플레이스. Contribute to Seungkyu-Han/PS_strategy development by creating an account on GitHub.
github.com
algospot.com :: BOARDCOVER
게임판 덮기 문제 정보 문제 H*W 크기의 게임판이 있습니다. 게임판은 검은 칸과 흰 칸으로 구성된 격자 모양을 하고 있는데 이 중 모든 흰 칸을 3칸짜리 L자 모양의 블록으로 덮고 싶습니다. 이
www.algospot.com
게임판 덮기 문제이다.
알고스팟에 제출을 해봤는데 nonzero return code...?? 라는 에러가 뜬다.
어차피 제출할 용도가 아닌 공부용이었으니 풀어보기만 하고 제출은 하지 않도록 하겠다.
좌표를 모두 돌며 확인하는 브루트포스 + 해당 경우에서 더 이상 답을 찾지 못하면 돌아오는 백트래킹 방법이다.
이 문제를 풀고 생각난 건데 브루트포스는 완전탐색이다. 따라서 확인 할 수 있는 모든 경우를 찾아야 한다.
이 문제에서도 놓을 수 있는 블록의 타입을 모두 찾아야 정답이 나온다.
만약 경우를 모두 찾지 못하면 정답보다 작은 값이, 경우를 중복으로 찾았다면 정답보다 큰 값이 나오게 될 것이다.
이 문제에서 좌표를 x, y라고 했을 때, 놓을 수 있는 블록의 종류이다.
block = [[[0, 0], [1, 0], [0, 1]], [[0, 0], [0, 1], [1, 1]], [[0, 0], [1, 0], [1, 1]], [[0, 0], [1, 0], [1, -1]]]
당연히 해당 좌표를 비우고 간다면 모든 게임판을 채울 수 없게 되고, 이 이외의 블록 종류들은 다른 칸에서 놓는 블록의 모양과 중복이 된다.
게임판을 받았을 때 다음으로 채워야 하는 좌표를 반환해주는 함수이다.
def find(h_len, w_len):
for q in range(h_len):
for r in range(w_len):
if board_list[q][r] == '.':
return [q, r]
return [-1, -1] # 모든 칸이 덮여있으면
모든 칸에 블록이 있다면 -1, -1을 리턴해주어 호출한 곳에 알려준다.
게임판에 해당 타입의 종류의 블록을 놓을 수 있는지 알려주는 함수이다.
def is_blank(x, y, block_type):
for q in range(3):
if 0 <= x + block[block_type][q][0] < h and 0 <= y + block[block_type][q][1] < w:
if board_list[x + block[block_type][q][0]][y + block[block_type][q][1]] == '#':
return False
return True
게임판을 '#'으로 덮어주거나, '.'으로 치워주는 함수이다.
def cover_block(x, y, block_type, blank_or_block):
for q in range(3):
board_list[x + block[block_type][q][0]][y + block[block_type][q][1]] = blank_or_block
백트래킹에서는 정답의 경우가 없으면 복구를 해줘야 하기 때문에 blank_or_block으로 '.'도 받아서 복구도 할 수 있도록 하였다.
block_type으로 블록의 종류를 받고 해당 칸 만큼 채워주거나 치워준다.
def solve(board_list, h, w):
global result
result = 0
# 놓을 수 있는 블록의 종류
block = [[[0, 0], [1, 0], [0, 1]], [[0, 0], [0, 1], [1, 1]], [[0, 0], [1, 0], [1, 1]], [[0, 0], [1, 0], [1, -1]]]
def cover():
global result
x, y = find(h, w)
if x == -1 and y == -1:
result += 1
return
for q in range(4):
if is_blank(x, y, q):
cover_block(x, y, q, '#')
cover()
cover_block(x, y, q, '.')
def find(h_len, w_len):
for q in range(h_len):
for r in range(w_len):
if board_list[q][r] == '.':
return [q, r]
return [-1, -1] # 모든 칸이 덮여있으면
def is_blank(x, y, block_type):
for q in range(3):
if 0 <= x + block[block_type][q][0] < h and 0 <= y + block[block_type][q][1] < w:
if board_list[x + block[block_type][q][0]][y + block[block_type][q][1]] == '#':
return False
return True
def cover_block(x, y, block_type, blank_or_block):
for q in range(3):
board_list[x + block[block_type][q][0]][y + block[block_type][q][1]] = blank_or_block
cover()
print(result)
사용한 함수의 전체이다.
함수 안에 함수들을 넣어서 최대한 깔끔하게 정답을 리턴할 수 있도록 했다.
cover() 함수에서 find를 좌표들을 돌며 채워주고 복구해주는 백트래킹 방법을 사용했다.
만약 find()에서 -1, -1을 리턴받으면 외부 전역 변수 result에 +1을 해준다.
import sys
result = 0
def solve(board_list, h, w):
global result
result = 0
# 놓을 수 있는 블록의 종류
block = [[[0, 0], [1, 0], [0, 1]], [[0, 0], [0, 1], [1, 1]], [[0, 0], [1, 0], [1, 1]], [[0, 0], [1, 0], [1, -1]]]
def cover():
global result
x, y = find(h, w)
if x == -1 and y == -1:
result += 1
return
for q in range(4):
if is_blank(x, y, q):
cover_block(x, y, q, '#')
cover()
cover_block(x, y, q, '.')
def find(h_len, w_len):
for q in range(h_len):
for r in range(w_len):
if board_list[q][r] == '.':
return [q, r]
return [-1, -1] # 모든 칸이 덮여있으면
def is_blank(x, y, block_type):
for q in range(3):
if 0 <= x + block[block_type][q][0] < h and 0 <= y + block[block_type][q][1] < w:
if board_list[x + block[block_type][q][0]][y + block[block_type][q][1]] == '#':
return False
return True
def cover_block(x, y, block_type, blank_or_block):
for q in range(3):
board_list[x + block[block_type][q][0]][y + block[block_type][q][1]] = blank_or_block
cover()
print(result)
for _ in range(int(sys.stdin.readline())):
H, W = map(int, sys.stdin.readline().split())
board = []
blank_cnt = 0
for i in range(H):
board.append(list(sys.stdin.readline().strip()))
blank_cnt += board[-1].count('.')
# 빈칸의 수가 3의 배수가 아니면 어차피 덮지 못하니 continue
if blank_cnt % 3 != 0:
print(0)
continue
solve(board, H, W)
사용한 코드의 전체이다.
브루트포스에서 가장 중요한 것은 탐색할 수 있는 모든 경우의 수를 찾는 것이다.
항상 생각하고 풀 수 있도록 하자!
'알고리즘 > 브루트포스' 카테고리의 다른 글
백준 4675 셀프 넘버 (1) | 2024.01.15 |
---|---|
백준 1065 한수 (0) | 2024.01.15 |
소풍 (1) | 2022.09.16 |
보글 게임 (1) | 2022.09.16 |
조합을 구하는 알고리즘 (0) | 2022.09.15 |