https://www.acmicpc.net/problem/18808
18808번: 스티커 붙이기
혜윤이는 최근에 다양한 대회를 참여하면서 노트북에 붙일 수 있는 스티커들을 많이 받았다. 스티커는 아래와 같이 사각 모눈종이 위에 인쇄되어 있으며, 스티커의 각 칸은 상하좌우로 모두 연
www.acmicpc.net
0. 문제
아래 규칙으로 노트북에 스티커를 붙인다.
- 스티커를 회전시키지 않고 모눈종이에서 떼어낸다.
- 다른 스티커와 겹치거나 노트북을 벗어나지 않으면서 스티커를 붙일 수 있는 위치를 찾는다. 붙일 수 있는 위치가 여러 개라면 가장 위, 그 중에서도 가장 왼쪽 위치에 붙인다.
- 선택한 위치에 스티커를 붙인다. 만약 스티커를 붙일 수 있는 위치가 전혀 없어서 스티커를 붙이지 못했다면, 스티커를 시계 방향으로 90도 회전한 뒤 2번 과정을 반복한다.
- 위의 과정을 네 번 반복해서 스티커를 0도, 90도, 180도, 270도 회전시켜 봤음에도 스티커를 붙이지 못했다면 해당 스티커를 붙이지 않고 버린다.
다음과 같은 스티커가 있으면 차례로 다음처럼 붙인다.
1. 아이디어
- 시뮬레이션은 레벨이 높아질수록 함수로 빼는 게 중요한 것 같다.
- 기본적으로 회전, 스티커 붙이는 함수로 나누려고 했다.
- 작성하다 보니 회전, 스티커 붙일 위치 찾는 함수, 붙일 수 있는지 확인하는 함수, 붙이는 함수로 나뉘었다.
- 90도 회전시키기
- 회전시키는 것은 예전에 많이 해봤어서 익숙한 코드를 그대로 썼다.
- ans = [i[::-1] for i in zip(*matrix)]
arr = [[1, 2, 3], [4, 5, 6], [7, 8, 9], [10, 11, 12]] # 전치행렬 arr_trans = [list(i) for i in zip(*arr)] # 시계 방향으로 90도 회전 arr_cw90_tuple = list(zip(*arr[::-1])) # arr_cw90_list1 = list(map(list, zip(*arr[::-1]))) arr_cw90_list2 = [list(i) for i in zip(*arr[::-1])] # 반시계 방향으로 90도 회전 arr_ccw90_tuple = list(zip(*arr))[::-1] # arr_ccw90_list1 = list(map(list, list(zip(*arr))[::-1])) arr_ccw90_list2 = [list(i) for i in list(zip(*arr))[::-1]]
- 스티커 붙이기
- 스티커 붙일 위치 찾기
- dr, dc로 노트북 영역을 움직여서 스티커 영역과 비교하도록 한다.
- 스티커를 붙일 수 있는지 확인한다.
- 스티커를 붙일 수 있으면 스티커를 붙인다.
- 스티커 붙일 수 있는지 확인하기
- 노트북과 스티커의 각 좌표의 값을 비교한다.
- 스티커의 값이 1인데 노트북 값도 1이면 스티커를 붙일 수 없다.
- 스티커 붙이기
- 노트북과 스티커의 각 좌표의 값을 비교한다.
- 스티커의 값이 1이면 노트북에 1을 쓰고, 0이면 넘어간다.
- 스티커 붙일 위치 찾기
2. 전체 코드
# 90도 회전
def rotate90(matrix: list) -> list:
ans = [i[::-1] for i in zip(*matrix)]
return ans
# 스티커 붙일 수 있는 위치인지 체크
def can_sticker(dr, dc):
for r in range(R):
for c in range(C):
# 범위 넘어가면 못 붙임
if not (0 <= r + dr < N and 0 <= c + dc < M):
return 0
# 노트북이랑 스티커가 겹치면 붙일 수 없음
if notebook[r + dr][c + dc] and sticker[r][c]:
return 0
# 모든 곳이 겹치지 않으면 붙일 수 있음
return 1
# 스티커 붙이기
def put_sticker(dr, dc):
for r in range(R):
for c in range(C):
if sticker[r][c]:
notebook[r + dr][c + dc] = 1
return 1
# 스티커 붙일 자리 찾기
def find_sticker_position_and_put():
# flag : 스티커 붙였는지
flag = 0
for dr in range(N - R + 1):
for dc in range(M - C + 1):
# 만약 스티커 붙일 수 있으면 스티커 붙이고 끝내기
if can_sticker(dr, dc):
flag = put_sticker(dr, dc)
return flag
return flag
N, M, K = map(int, input().split())
notebook = [[0] * M for _ in range(N)]
for _ in range(K):
R, C = map(int, input().split())
sticker = [list(map(int, input().split())) for _ in range(R)]
# 4방향 회전하면서 위치 찾기
for rotate_num in range(4):
flag = find_sticker_position_and_put()
# 스티커 붙일 수 있는 자리 찾고 붙였으면 끝
if flag:
break
# 못찾았으면 회전하고 R, C 바꾸기
else:
sticker = rotate90(sticker)
R, C = C, R
# 스티커가 붙은 칸의 수 출력
ans = 0
for i in range(N):
ans += sum(notebook[i])
print(ans)
'APS > BOJ' 카테고리의 다른 글
[Python / BOJ 1167] 트리의 지름 (0) | 2022.03.23 |
---|---|
[Python / BOJ 13459] 구슬 탈출 (0) | 2022.03.03 |
[Python / BOJ 10844] 쉬운 계단 수 (0) | 2022.02.22 |
[Python / BOJ 12865] 평범한 배낭 (0) | 2022.01.24 |
[Python / BOJ 3151] 합이 0 (0) | 2022.01.17 |