https://www.acmicpc.net/problem/23288
링크 참조
입력
첫째 줄에 지도의 세로 크기 N, 가로 크기 M (2 ≤ N, M ≤ 20), 그리고 이동하는 횟수 K (1 ≤ K ≤ 1,000)가 주어진다.
둘째 줄부터 N개의 줄에 지도에 쓰여 있는 수가 북쪽부터 남쪽으로, 각 줄은 서쪽부터 동쪽 순서대로 주어진다. 지도의 각 칸에 쓰여 있는 수는 10 미만의 자연수이다.
출력
첫째 줄에 각 이동에서 획득하는 점수의 합을 출력한다.
주사위 이동시의 변화를 알아야 한다. 주사위 도면은 아래와 같은 방식으로 생각한다. (리스트 작성시, dice = [0, 1, 2, 3, 4, 5] 와 같음.)
위의 주사위를 가지고, 각각 동, 서, 남, 북으로 움직였을 시 숫자의 변화를 파악한다. (맨 왼쪽의 잘린 숫자는 5이다.)
이로써 주사위가 이동 후, 어떤 식으로 숫자의 변화가 있는지 알 수 있다.
각 이동시 변화가 담겨있는 move_map 배열을 만들어 준다.
move_map = [[4, 1, 3, 6, 5, 2], [3, 2, 6, 4, 1, 5],
[2, 6, 3, 1, 5, 4], [5, 2, 1, 4, 6, 3]]
def move_dice(direction):
global dice
temp = dice[:]
for i in range(len(dice)):
temp[i] = dice[move_map[direction][i]]
dice = temp[:]
def point_count(cx, cy, B):
q = deque()
check = [[False] * M for _ in range(N)]
cnt = 0
q.append((cy, cx))
check[cy][cx] = True
while q:
y, x = q.popleft()
cnt += 1
for i in range(4):
nx = x + dx[i]
ny = y + dy[i]
if ny < 0 or nx < 0 or ny >= N or nx >= M or check[ny][nx]:
continue
if Board[ny][nx] == B:
check[ny][nx] = True
q.append((ny, nx))
return cnt * B
#전체코드#
from collections import deque
def move_dice(direction):
global dice
temp = dice[:] #temp에 현재 주사위 숫자 위치를 복사
for i in range(len(dice)):
# 이동 후 주사위의 숫자와 현재 주사위 숫자의 위치를 교체해준다.
temp[i] = dice[move_map[direction][i]]
dice = temp[:] #다음 주사위 숫자 위치를 dice로 복사
def point_count(cx, cy, B):
q = deque()
check = [[False] * M for _ in range(N)]
cnt = 0
q.append((cy, cx))
check[cy][cx] = True
while q:
y, x = q.popleft()
cnt += 1 #같은 칸이 하나 있는 것이기 때문에 +1
for i in range(4):
nx = x + dx[i]
ny = y + dy[i]
#이동할 수 없거나 이미 확인된 곳이라면 넘어간다.
if ny < 0 or nx < 0 or ny >= N or nx >= M or check[ny][nx]:
continue
#이동 후 현재 칸의 값과 같은 숫자라면 check해주고 q에 넣어준다.
if Board[ny][nx] == B:
check[ny][nx] = True
q.append((ny, nx))
return cnt * B
N, M, K = map(int, input().split())
Board = [list(map(int, input().split())) for _ in range(N)]
# dx, dy를 동,서,남,북 순으로 입력받을 수 있게 세팅.
dx = [1, 0, -1, 0]
dy = [0, 1, 0, -1]
direction = 0
dice = [6, 4, 2, 3, 5, 1] #현재 주사위의 숫자(구현과정 1번 그림 참고)
# move_map = [[4, 1, 3, 6, 5, 2], [3, 2, 6, 4, 1, 5], [2, 6, 3, 1, 5, 4], [5, 2, 1, 4, 6, 3]]
move_map = [[], [], [], []]
move_map[0] = [3, 0, 2, 5, 4, 1]
move_map[1] = [4, 1, 0, 3, 5, 2]
move_map[2] = [1, 5, 2, 0, 4, 3]
move_map[3] = [2, 1, 5, 3, 0, 4]
#dx, dy가 동 서 남 북 순이기 때문에 주사위의 이동 후 숫자도 순서대로 맞춰줌
# 0 1 2 3
current_location = (0, 0) #시작 위치
total_point = 0
for i in range(K):
# 처음은 오른쪽으로 향하기 때문에, direction = 0 그대로 더해줌
ny = current_location[0] + dy[direction]
nx = current_location[1] + dx[direction]
# 갈 수 없는 상황일 경우, 반대로 바꿔줌
if ny < 0 or nx < 0 or ny >= N or nx >= M:
#비트연산자로 반대 방향으로 바꿔준 후, ny, nx를 다시 조정
direction = direction ^ 2
ny = current_location[0] + dy[direction]
nx = current_location[1] + dx[direction]
current_location = (ny, nx) #현재 위치를 ny, nx로 입력
move_dice(direction) # 주사위 숫자 변경
B = Board[ny][nx] # 현재 칸의 숫자 값
point = point_count(nx, ny, B)
total_point += point
A = dice[0] # 주사위의 아랫면
if A > B: #주사위 아랫면이 더 클 경우 시계방향 90도
direction = (direction + 1) % 4
elif A < B: #주사위 아랫면이 더 작을 경우 반시계방향 90도
direction = (direction - 1) % 4
print(total_point)
머리로만 생각하면 굴릴 때마다 점수 구하고, 주사위 숫자만 바꿔주고, 다음 방향만 정해주면 되는 것 같은데 하나씩 로직을 구현하는 과정이 역시 쉽지 않았다..
막상 하고나니 코드 길이도 짧고, 직관적으로 생겨서 다음엔 더 쉽게 풀 수 있을 것 같다
1000번 반복해야 하는 마지막 테스트 케이스에서 틀려서 시간이 오래 걸렸는데, 주사위 이동 방향과 dx, dy를 맞춰주지 않아서 그랬었다! 다행인건 함수를 하나씩 짤때마다 맞는지 틀리는지 확인해줘서 엄청 헤매진 않았다.
찾았다!숭이 이모티콘을 좋아하는 분의 영상을 보고 도움을 많이 받았다...😅