https://www.acmicpc.net/problem/23288
23288번: 주사위 굴리기 2
크기가 N×M인 지도가 존재한다. 지도의 오른쪽은 동쪽, 위쪽은 북쪽이다. 지도의 좌표는 (r, c)로 나타내며, r는 북쪽으로부터 떨어진 칸의 개수, c는 서쪽으로부터 떨어진 칸의 개수이다. 가장 왼
www.acmicpc.net
문제
크기가 N×M인 지도가 존재한다. 지도의 오른쪽은 동쪽, 위쪽은 북쪽이다. 지도의 좌표는 (r, c)로 나타내며, r는 북쪽으로부터 떨어진 칸의 개수, c는 서쪽으로부터 떨어진 칸의 개수이다. 가장 왼쪽 위에 있는 칸의 좌표는 (1, 1)이고, 가장 오른쪽 아래에 있는 칸의 좌표는 (N, M)이다. 이 지도의 위에 주사위가 하나 놓여져 있으며, 주사위의 각 면에는 1보다 크거나 같고, 6보다 작거나 같은 정수가 하나씩 있다. 주사위 한 면의 크기와 지도 한 칸의 크기는 같고, 주사위의 전개도는 아래와 같다.
2
4 1 3
5
6
주사위는 지도 위에 윗 면이 1이고, 동쪽을 바라보는 방향이 3인 상태로 놓여져 있으며, 놓여져 있는 곳의 좌표는 (1, 1) 이다. 지도의 각 칸에도 정수가 하나씩 있다. 가장 처음에 주사위의 이동 방향은 동쪽이다. 주사위의 이동 한 번은 다음과 같은 방식으로 이루어진다.
- 주사위가 이동 방향으로 한 칸 굴러간다. 만약, 이동 방향에 칸이 없다면, 이동 방향을 반대로 한 다음 한 칸 굴러간다.
- 주사위가 도착한 칸 (x, y)에 대한 점수를 획득한다.
- 주사위의 아랫면에 있는 정수 A와 주사위가 있는 칸 (x, y)에 있는 정수 B를 비교해 이동 방향을 결정한다.
- A > B인 경우 이동 방향을 90도 시계 방향으로 회전시킨다.
- A < B인 경우 이동 방향을 90도 반시계 방향으로 회전시킨다.
- A = B인 경우 이동 방향에 변화는 없다.
칸 (x, y)에 대한 점수는 다음과 같이 구할 수 있다. (x, y)에 있는 정수를 B라고 했을때, (x, y)에서 동서남북 방향으로 연속해서 이동할 수 있는 칸의 수 C를 모두 구한다. 이때 이동할 수 있는 칸에는 모두 정수 B가 있어야 한다. 여기서 점수는 B와 C를 곱한 값이다.
보드의 크기와 각 칸에 있는 정수, 주사위의 이동 횟수 K가 주어졌을때, 각 이동에서 획득하는 점수의 합을 구해보자.
이 문제의 예제 1부터 7은 같은 지도에서 이동하는 횟수만 증가시키는 방식으로 구성되어 있다. 예제 8은 같은 지도에서 이동하는 횟수를 매우 크게 만들었다.
입력
첫째 줄에 지도의 세로 크기 N, 가로 크기 M (2 ≤ N, M ≤ 20), 그리고 이동하는 횟수 K (1 ≤ K ≤ 1,000)가 주어진다.
둘째 줄부터 N개의 줄에 지도에 쓰여 있는 수가 북쪽부터 남쪽으로, 각 줄은 서쪽부터 동쪽 순서대로 주어진다. 지도의 각 칸에 쓰여 있는 수는 10 미만의 자연수이다.
출력
첫째 줄에 각 이동에서 획득하는 점수의 합을 출력한다.
해당 문제는 내가 주사위를 어떠한 방식으로 굴리느냐가 핵심인 것 같다.
주사위의 각 위치를 방향으로 설정하고 이후에 회전할 때 어더한 방식으로 움직일지 정하는 것을 먼저 했다.
주사위 모양은 주어졌기에 나는 dictionary 형태로 주사위를 저장했고
주사위가 움직일 때 변하는 방식을 함수로 구성했다.
# 주사위 움직이는 방식
def DiceRotation(dices, d):
if d == 0:
dices[0], dices[2], dices[4], dices[5] = dices[2], dices[4], dices[5], dices[0]
elif d == 1:
dices[1], dices[2], dices[3], dices[5] = dices[5], dices[1], dices[2], dices[3]
elif d == 2:
dices[0], dices[2], dices[4], dices[5] = dices[5], dices[0], dices[2], dices[4]
elif d == 3:
dices[1], dices[2], dices[3], dices[5] = dices[2], dices[3], dices[5], dices[1]
return dices
# 주사위 모양
dices = {0: 2, 1: 4, 2: 1, 3: 3, 4: 5, 5: 6}
n, m, k = map(int, input().split())
주사위가 움직일때마다 각 board의 같은 수의 갯수를 구하는데
문제를 읽어봤을때 값들이 고정적이여서 과정을 미리 구해서 새 2차원 리스트에 저장을 한 뒤 문제를 풀어나갔다.
이러한 방식이 k가 증가함에 따라 시간이 이득이라 판단했다.
# 점수판 및 점수판 별 BFS 값
boards = [list(map(int, input().split())) for _ in range(n)]
cnt_boards = [[BFS(boards, row, col, n, m) for col in range(m)] for row in range(n)]
d = 1
row, col = 0, 0
answer = 0
# 중복 값 갯수 찾기 위한 BFS 실행
def BFS(boards, r, c, n, m):
ls = deque()
cnt = 1
visited = [[False for _ in range(m)] for _ in range(n)]
ls.append((r, c))
visited[r][c] = True
while ls:
y, x = ls.popleft()
for idx in range(4):
nj, ni = y + dr[idx], x + dc[idx]
if 0 <= nj < n and 0 <= ni < m and not visited[nj][ni] and boards[r][c] == boards[nj][ni]:
visited[nj][ni] = True
ls.append((nj, ni))
cnt += 1
return cnt
이렇게 미리 설정을 다했으니 주사위를 굴려보면 된다.
이 문제는 크게 설명할 부분이 없고
주어진 제한을 잘 수행하기만 하면 된다.
for _ in range(k):
# 주사위 위치 추종
if not (0 <= row + dr[d] < n and 0 <= col + dc[d] < m):
d = (d + 2) % 4
# 정해진 방향으로 주사위 이동 및 주사위 회전
row, col = row + dr[d], col + dc[d]
dices = DiceRotation(dices, d)
# boards의 값과 같은 것이 몇 개인지 찾고, 갯수 * boards[row][col]을 가산
answer += cnt_boards[row][col] * boards[row][col]
# 방향 전환 조건
if dices[5] < boards[row][col]:
d = (d - 1) % 4
elif dices[5] > boards[row][col]:
d = (d + 1) % 4
이렇게 방향 전환과 갯수를 answer를 잘 더해준다.
아래 전체 코드를 보자.
import sys
from collections import deque
input = sys.stdin.readline
# d에 따른 추종 방향
dr = [-1, 0, 1, 0]
dc = [0, 1, 0, -1]
# 중복 값 갯수 찾기 위한 BFS 실행
def BFS(boards, r, c, n, m):
ls = deque()
cnt = 1
visited = [[False for _ in range(m)] for _ in range(n)]
ls.append((r, c))
visited[r][c] = True
while ls:
y, x = ls.popleft()
for idx in range(4):
nj, ni = y + dr[idx], x + dc[idx]
if 0 <= nj < n and 0 <= ni < m and not visited[nj][ni] and boards[r][c] == boards[nj][ni]:
visited[nj][ni] = True
ls.append((nj, ni))
cnt += 1
return cnt
# 주사위 움직이는 방식
def DiceRotation(dices, d):
if d == 0:
dices[0], dices[2], dices[4], dices[5] = dices[2], dices[4], dices[5], dices[0]
elif d == 1:
dices[1], dices[2], dices[3], dices[5] = dices[5], dices[1], dices[2], dices[3]
elif d == 2:
dices[0], dices[2], dices[4], dices[5] = dices[5], dices[0], dices[2], dices[4]
elif d == 3:
dices[1], dices[2], dices[3], dices[5] = dices[2], dices[3], dices[5], dices[1]
return dices
# 주사위 모양
dices = {0: 2, 1: 4, 2: 1, 3: 3, 4: 5, 5: 6}
n, m, k = map(int, input().split())
# 점수판 및 점수판 별 BFS 값
boards = [list(map(int, input().split())) for _ in range(n)]
cnt_boards = [[BFS(boards, row, col, n, m) for col in range(m)] for row in range(n)]
d = 1
row, col = 0, 0
answer = 0
for _ in range(k):
# 주사위 위치 추종
if not (0 <= row + dr[d] < n and 0 <= col + dc[d] < m):
d = (d + 2) % 4
# 정해진 방향으로 주사위 이동 및 주사위 회전
row, col = row + dr[d], col + dc[d]
dices = DiceRotation(dices, d)
# boards의 값과 같은 것이 몇 개인지 찾고, 갯수 * boards[row][col]을 가산
answer += cnt_boards[row][col] * boards[row][col]
# 방향 전환 조건
if dices[5] < boards[row][col]:
d = (d - 1) % 4
elif dices[5] > boards[row][col]:
d = (d + 1) % 4
print(answer)
해당 게시글이 도움이 되었다면,
'IT 톺아보기 > 알고리즘' 카테고리의 다른 글
백준 1007번 | 벡터 매칭 - python (1) | 2022.11.08 |
---|---|
백준 1005번 ACM Craft - python (0) | 2022.11.03 |
백준 23290 | 마법사 상어와 복제 - python (1) | 2022.10.13 |
백준 23291번 | 어항 정리 - python (0) | 2022.10.13 |
백준 16236번 | 아기 상어 - python (0) | 2022.10.07 |