[Samsung] 2022-1 오전 2번 예술성
        
         
  
      [Samsung] 2022-1 오전 2번 예술성
Question
Language: Python
Difficulty: Gold 3
해당 문제는 주어진 문제의 시뮬레이션을 구현하는 문제이며 bfs가 활용된다.
시뮬레이션 과정은 아래와 같다.
- 예술성 점수 구하기
- 배열의 회전
구체적인 과정을 살펴보자
- 예술성 점수 구하기
예술성 점수를 구하는 과정은 크게 3과정이다.
우선, bfs을 활용하여 각각의 component을 찾아주는 작업을 진행한다. 추가적으로 각각의 좌표가 해당하는 그룹 인덱스를 저장하는 group_map도 생성해서 반환한다.
def get_components():
    #각 좌표에 대해 각각 어느 그룹에 속하는지를 나타내는 배열
    group_map=[[0]*n for _ in range(n)]
    #각각의 집합들을 찾는 부분
    visited=[[False] * n for _ in range(n)]
    #각각의 그룹들을 저장하는 배열
    components=[]
    group_index=0
    for start_row in range(n):
        for start_col in range(n):
            #방문 여부
            if visited[start_row][start_col]:
                continue
            queue=deque([(start_row,start_col)])
            
            group_value=board[start_row][start_col]
            component=[group_value]
            
            while queue:
                row,col=queue.popleft()
                if visited[row][col]:
                    continue
                
                visited[row][col]=True
                component.append((row,col))
                group_map[row][col]=group_index
                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
                    
                    if board[next_row][next_col] == group_value:
                        queue.append((next_row,next_col))
                    
            components.append(component)
            group_index+=1
    return group_map,components
그런 다음, 각 그룹 간 인접한 변의 갯수를 구하기 위해 각 그룹 내에 있는 좌표들에 대해 인접 좌표를 조사해서 현재 그룹과 인접한 좌표가 속해있는 그룹에 대한 adjacent_counts 배열 값을 갱신한다.
이 과정을 통해 모든 (team_a,team_b)에 대한 team_a <-> team_b 간에 인접한 변의 갯수를 저장하게 된다. 한번에 일괄적으로 저장하므로써 이후, combination 작업에서 불필요한 중복 탐색을 줄일 수 있다.
def get_adjacent_counts(group_map,components,group_length):
    adjacent_counts=[[0] * group_length for _ in range(group_length)]
    for index in range(group_length):
        component=components[index]
        for row,col in component[1:]:
            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
                
                #해당 그룹과 다른 그룹에 대한 인접 변의 갯수를 증가시킨다.
                adjacent_counts[index][group_map[next_row][next_col]]+=1
    return adjacent_counts
마지막으로, 모든 그룹의 조합에 대해 예술성 점수를 구한다
harmony_points=0
#a,b 조합에 대하여 조화로움 점수를 구하는 작업을 진행한다.
for combination in combinations(range(group_length),2):
    group_a_index,group_b_index=combination
    group_a_value=components[group_a_index][0]
    group_b_value=components[group_b_index][0]
    adjacent_count=adjacent_counts[group_a_index][group_b_index]
    point=(len(components[group_a_index][1:])+len(components[group_b_index][1:])) * group_a_value * group_b_value * adjacent_count
    harmony_points+=point
return harmony_points
- 배열 회전하기
배열 회전은 크게 2가지 과정으로 각 4개의 귀퉁이에 있는 정사각형에 대한 회전과 중앙에 위치한 십자가의 회전이 동반된다.
정사각형의 회전은 아래의 함수와 같이 구현한다. 배열의 회전 과정에서 시작 좌표에 대한 평행이동을 적용하여 회전 이후 기존의 위치에 저장될 수 있도록 구현하여 회전 간 독립성을 유지가 가능하다.
def rotate_quarter(new_board,start_row,start_col,end_row,end_col):
    for row in range(start_row,start_row+n//2):
        for col in range(start_col,start_col+n//2):
            new_board[start_row+col-start_col][start_col+end_row-row]=board[row][col]
#좌상단
rotate_quarter(new_board,0,0,n//2-1,n//2-1)
#우상단
rotate_quarter(new_board,0,n//2+1,n//2-1,n-1)
#좌하단
rotate_quarter(new_board,n//2+1,0,n-1,n//2-1)
#우하단
rotate_quarter(new_board,n//2+1,n//2+1,n-1,n-1)
십자가를 구하는 부분은 아래와 같다
#십자가의 수평선
for col in range(n):
    new_board[n//2][col]=board[col][n//2]
#십자가의 수직선
for row in range(n):
    new_board[row][n//2]=board[n//2][n-row-1]
Solution
from collections import deque
from itertools import combinations
def get_components():
    #각 좌표에 대해 각각 어느 그룹에 속하는지를 나타내는 배열
    group_map=[[0]*n for _ in range(n)]
    #각각의 집합들을 찾는 부분
    visited=[[False] * n for _ in range(n)]
    #각각의 그룹들을 저장하는 배열
    components=[]
    group_index=0
    for start_row in range(n):
        for start_col in range(n):
            #방문 여부
            if visited[start_row][start_col]:
                continue
            queue=deque([(start_row,start_col)])
            
            group_value=board[start_row][start_col]
            component=[group_value]
            
            while queue:
                row,col=queue.popleft()
                if visited[row][col]:
                    continue
                
                visited[row][col]=True
                component.append((row,col))
                group_map[row][col]=group_index
                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
                    
                    if board[next_row][next_col] == group_value:
                        queue.append((next_row,next_col))
                    
            components.append(component)
            group_index+=1
    return group_map,components
def get_adjacent_counts(group_map,components,group_length):
    adjacent_counts=[[0] * group_length for _ in range(group_length)]
    for index in range(group_length):
        component=components[index]
        for row,col in component[1:]:
            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
                
                #해당 그룹과 다른 그룹에 대한 인접 변의 갯수를 증가시킨다.
                adjacent_counts[index][group_map[next_row][next_col]]+=1
    return adjacent_counts
def get_score():    
    group_map,components=get_components()
    group_length=len(components)
    adjacent_counts=get_adjacent_counts(group_map,components,group_length)
    harmony_points=0
    #a,b 조합에 대하여 조화로움 점수를 구하는 작업을 진행한다.
    for combination in combinations(range(group_length),2):
        group_a_index,group_b_index=combination
        group_a_value=components[group_a_index][0]
        group_b_value=components[group_b_index][0]
        adjacent_count=adjacent_counts[group_a_index][group_b_index]
        point=(len(components[group_a_index][1:])+len(components[group_b_index][1:])) * group_a_value * group_b_value * adjacent_count
        harmony_points+=point
    return harmony_points
def rotate_quarter(new_board,start_row,start_col,end_row,end_col):
    for row in range(start_row,start_row+n//2):
        for col in range(start_col,start_col+n//2):
            new_board[start_row+col-start_col][start_col+end_row-row]=board[row][col]
    
def rotate():
    new_board=[[0] * n for _ in range(n)]
    #좌상단
    rotate_quarter(new_board,0,0,n//2-1,n//2-1)
    #우상단
    rotate_quarter(new_board,0,n//2+1,n//2-1,n-1)
    #좌하단
    rotate_quarter(new_board,n//2+1,0,n-1,n//2-1)
    #우하단
    rotate_quarter(new_board,n//2+1,n//2+1,n-1,n-1)
    #십자가의 수평선
    for col in range(n):
        new_board[n//2][col]=board[col][n//2]
    #십자가의 수직선
    for row in range(n):
        new_board[row][n//2]=board[n//2][n-row-1]
    
    #회전을 기존 맵에 반영
    for row in range(n):
        for col in range(n):
            board[row][col]=new_board[row][col]
def print_board(title,board):
    print(title)
    for row in board:
        print(*row)   
def solution():
    total_points=0
    for _ in range(4):
        total_points+=get_score()
        rotate()
    print(total_points)
if __name__ == "__main__":
    n=int(input())
    board=[list(map(int,input().split())) for _ in range(n)]
    dy=[-1,0,1,0]
    dx=[0,1,0,-1]
    solution()
 
      
댓글남기기