[Samsung] 2021-2 오전 1번 정육면체 한번 더 굴리기
[Samsung] 2021-2 오전 1번 정육면체 한번 더 굴리기
Question
Language: Python
Difficulty: Gold 3
해당 문제에서 구현해야될 부분은 크게 2가지이다.
- bfs을 통해 component 찾기
- 주사위의 회전 구현
각 세부 과정은 아래와 같다
- Component 찾기
bfs을 활용하여 인접한 칸에 같은 값을 가지는 좌표끼리 묶어서 component을 구성한다.
def find_components():
component_index=0
component_map=[[0] * n for _ in range(n)]
components=[]
visited=[[False] * n for _ in range(n)]
for start_row in range(n):
for start_col in range(n):
if not visited[start_row][start_col]:
queue=deque([(start_row,start_col)])
value=board[start_row][start_col]
score=0
while queue:
row,col=queue.popleft()
if visited[row][col]:
continue
visited[row][col]=True
#각 좌표가 포함된 component의 index 저장
component_map[row][col]=component_index
score+=value
for dir in range(4):
next_row=row+dy[dir]
next_col=col+dx[dir]
#범위를 벗어나는 경우
if next_row < 0 or next_row>=n or next_col< 0 or next_col>=n:
continue
#인접한 칸이 같은 값을 가지지 않은 경우 component에 포함하지 않는다.
if board[next_row][next_col] != value:
continue
queue.append((next_row,next_col))
components.append(score)
component_index+=1
return component_map,components
- 주사위의 회전
각 방향에 따라 rows,cols을 변경해주는 작업을 진행한다. 주사위 굴리기과 동일한 방식으로 구현하였다.
#북쪽 이동
if next_dice_dir ==0:
dice_rows.insert(0,dice_rows.pop())
dice_cols[1]=dice_rows[1]
#동쪽 이동
elif next_dice_dir ==1:
dice_cols.append(dice_rows.pop())
dice_rows.append(dice_cols.pop(0))
dice_rows[1]=dice_cols[1]
#남쪽 이동
elif next_dice_dir==2:
dice_rows.append(dice_rows.pop(0))
dice_cols[1]=dice_rows[1]
#서쪽이동
elif next_dice_dir==3:
dice_cols.insert(0,dice_rows.pop())
dice_rows.append(dice_cols.pop())
dice_rows[1]=dice_cols[1]
위의 2가지 연산만 구현하면 나머지 과정은 어렵지 않게 구현할 수 있다.
Solution
from collections import deque
def find_components():
component_index=0
component_map=[[0] * n for _ in range(n)]
components=[]
visited=[[False] * n for _ in range(n)]
for start_row in range(n):
for start_col in range(n):
if not visited[start_row][start_col]:
queue=deque([(start_row,start_col)])
value=board[start_row][start_col]
score=0
while queue:
row,col=queue.popleft()
if visited[row][col]:
continue
visited[row][col]=True
#각 좌표가 포함된 component의 index 저장
component_map[row][col]=component_index
score+=value
for dir in range(4):
next_row=row+dy[dir]
next_col=col+dx[dir]
#범위를 벗어나는 경우
if next_row < 0 or next_row>=n or next_col< 0 or next_col>=n:
continue
#인접한 칸이 같은 값을 가지지 않은 경우 component에 포함하지 않는다.
if board[next_row][next_col] != value:
continue
queue.append((next_row,next_col))
components.append(score)
component_index+=1
return component_map,components
def first_move(dice_row,dice_col,dice_rows,dice_cols):
next_dice_row=dice_row+dy[1]
next_dice_col=dice_col+dx[1]
dice_cols.append(dice_rows.pop())
dice_rows.append(dice_cols.pop(0))
dice_rows[1]=dice_cols[1]
return next_dice_row,next_dice_col
#주사위의 이동 수행
def move_dice(dice_row,dice_col,dice_dir,dice_rows,dice_cols):
next_dice_dir=dice_dir
#바닥면에 적혀있는 숫자보다 주사위의 알랫면 숫자가 큰 경우 시계방향 회전
if board[dice_row][dice_col] < dice_rows[1]:
next_dice_dir=(dice_dir+1)%4
#작은 경우에는 반시계 방향 회전
elif board[dice_row][dice_col] > dice_rows[1]:
next_dice_dir=(dice_dir-1)%4
next_dice_row=dice_row+dy[next_dice_dir]
next_dice_col=dice_col+dx[next_dice_dir]
#범위를 벗어나는 경우 반대방향으로 한 칸 이동
if next_dice_row < 0 or next_dice_row>=n or next_dice_col< 0 or next_dice_col>=n:
next_dice_dir=(next_dice_dir+2)%4
next_dice_row=dice_row+dy[next_dice_dir]
next_dice_col=dice_col+dx[next_dice_dir]
#주사위 이동 실행
#북쪽 이동
if next_dice_dir ==0:
dice_rows.insert(0,dice_rows.pop())
dice_cols[1]=dice_rows[1]
#동쪽 이동
elif next_dice_dir ==1:
dice_cols.append(dice_rows.pop())
dice_rows.append(dice_cols.pop(0))
dice_rows[1]=dice_cols[1]
#남쪽 이동
elif next_dice_dir==2:
dice_rows.append(dice_rows.pop(0))
dice_cols[1]=dice_rows[1]
#서쪽이동
elif next_dice_dir==3:
dice_cols.insert(0,dice_rows.pop())
dice_rows.append(dice_cols.pop())
dice_rows[1]=dice_cols[1]
return next_dice_row,next_dice_col,next_dice_dir
def solution():
#모든 컴포넌트를 찾는 과정을 진행한다.
component_map,components=find_components()
#초기 주사위 정보 초기화
dice_row,dice_col,dice_dir=0,0,1
dice_rows=[5,6,2,1]
dice_cols=[4,6,3]
total_score=0
#처음 이동 수행
dice_row,dice_col=first_move(dice_row,dice_col,dice_rows,dice_cols)
total_score+=components[component_map[dice_row][dice_col]]
for _ in range(1,m):
dice_row,dice_col,dice_dir=move_dice(dice_row,dice_col,dice_dir,dice_rows,dice_cols)
score=components[component_map[dice_row][dice_col]]
total_score+=score
print(total_score)
if __name__ == "__main__":
n,m=map(int,(input().split()))
board=[list(map(int,input().split())) for _ in range(n)]
dy=[-1,0,1,0]
dx=[0,1,0,-1]
solution()
Solution 2
위에서는 dice_row,dice_col,dice_dir,dice_rows,dice_cols을 분리하였지만 아래와 같이 class로 묶어서 구현할 수 있다.
from collections import deque
class Dice:
def __init__(self):
self.row=0
self.col=0
self.dir=1
self.back=5
self.bottom=6
self.front=2
self.top=1
self.left=4
self.right=3
def roll_north(self):
self.back,self.bottom,self.front,self.top=self.top,self.back,self.bottom,self.front
def roll_south(self):
self.back,self.bottom,self.front,self.top=self.bottom,self.front,self.top,self.back
def roll_east(self):
self.left,self.bottom,self.right,self.top=self.bottom,self.right,self.top,self.left
def roll_west(self):
self.left,self.bottom,self.right,self.top=self.top,self.left,self.bottom,self.right
def find_components():
component_index=0
component_map=[[0] * n for _ in range(n)]
components=[]
visited=[[False] * n for _ in range(n)]
for start_row in range(n):
for start_col in range(n):
if not visited[start_row][start_col]:
queue=deque([(start_row,start_col)])
value=board[start_row][start_col]
score=0
while queue:
row,col=queue.popleft()
if visited[row][col]:
continue
visited[row][col]=True
#각 좌표가 포함된 component의 index 저장
component_map[row][col]=component_index
score+=value
for dir in range(4):
next_row=row+dy[dir]
next_col=col+dx[dir]
#범위를 벗어나는 경우
if next_row < 0 or next_row>=n or next_col< 0 or next_col>=n:
continue
#인접한 칸이 같은 값을 가지지 않은 경우 component에 포함하지 않는다.
if board[next_row][next_col] != value:
continue
queue.append((next_row,next_col))
components.append(score)
component_index+=1
return component_map,components
def first_move(dice):
dice.row=dice.row+dy[dice.dir]
dice.col=dice.col+dx[dice.dir]
dice.roll_east()
#주사위의 이동 수행
def move_dice(dice):
dice_row,dice_col,dice_dir=dice.row,dice.col,dice.dir
next_dice_dir=dice_dir
#바닥면에 적혀있는 숫자보다 주사위의 알랫면 숫자가 큰 경우 시계방향 회전
if board[dice_row][dice_col] < dice.bottom:
next_dice_dir=(dice_dir+1)%4
#작은 경우에는 반시계 방향 회전
elif board[dice_row][dice_col] > dice.bottom:
next_dice_dir=(dice_dir-1)%4
next_dice_row=dice_row+dy[next_dice_dir]
next_dice_col=dice_col+dx[next_dice_dir]
#범위를 벗어나는 경우 반대방향으로 한 칸 이동
if next_dice_row < 0 or next_dice_row>=n or next_dice_col< 0 or next_dice_col>=n:
next_dice_dir=(next_dice_dir+2)%4
next_dice_row=dice_row+dy[next_dice_dir]
next_dice_col=dice_col+dx[next_dice_dir]
#북
if next_dice_dir==0:
dice.roll_north()
#동
elif next_dice_dir==1:
dice.roll_east()
#남
elif next_dice_dir==2:
dice.roll_south()
#서
else:
dice.roll_west()
#주사위 이동 실행
dice.row,dice.col,dice.dir=next_dice_row,next_dice_col,next_dice_dir
def solution():
#모든 컴포넌트를 찾는 과정을 진행한다.
component_map,components=find_components()
#초기 주사위 정보 초기화
dice=Dice()
total_score=0
#처음 이동 수행
first_move(dice)
total_score+=components[component_map[dice.row][dice.col]]
for _ in range(1,m):
move_dice(dice)
score=components[component_map[dice.row][dice.col]]
total_score+=score
print(total_score)
if __name__ == "__main__":
n,m=map(int,(input().split()))
board=[list(map(int,input().split())) for _ in range(n)]
dy=[-1,0,1,0]
dx=[0,1,0,-1]
solution()
댓글남기기