티스토리 뷰

https://www.acmicpc.net/problem/16935

 

16935번: 배열 돌리기 3

크기가 N×M인 배열이 있을 때, 배열에 연산을 R번 적용하려고 한다. 연산은 총 6가지가 있다. 1번 연산은 배열을 상하 반전시키는 연산이다. 1 6 2 9 8 4 → 4 2 9 3 1 8 7 2 6 9 8 2 → 9 2 3 6 1 5 1 8 3 4 2 9 →

www.acmicpc.net


1. 접근 방식

  • 각 연산을 처리하는 함수를 구현하자.

각 함수는 인자로 기존 배열을 받고, 연산을 적용한 결과(배열)을 반환한다. 함수 내부에서 일어나는 일이 외부에 영향을 끼치고 싶지 않았기 때문에 이와 같이 배열을 인자로 받고, 새 배열을 반환하는 방식으로 구현하고자 한다.

 

  • 인덱싱과 리스트 comprehension을 활용하자.

연산 1 ~ 4는 인덱싱과 리스트 comprehension으로 모두 간단하게 해결할 수 있다.

그 중 연산 3을 살펴보자.

 

연산3 전 배열과 후 배열

위 그림에서 왼쪽은 입력 배열이고, 오른쪽은 연산3이 처리된 결과이다. 오른쪽 배열을 얻기 위한 과정은 크게 2가지로 나뉜다.

 

과정1: 열별로 접근한다.

첫째, 기존 배열을 열을 기준으로 접근한다. 열별로 접근하는 코드는 아래와 같다.

[ [ ... ] for i in range(len(arr[0])) ] # [ ... ]은 과정 2 코드

 

과정2: 각 열에서 행은 거꾸로 접근한다.

둘째, 각 열에서 행은 거꾸로 접근한다. 즉, 0행부터가 아니라, 5행부터 접근하는 것이다. 따라서 위쪽처럼 1 7 1 7 9 4가 아니라, 아래쪽처럼 4 9 7 1 7 1의 결과가 나와야 옳다.

[row[i] for row in arr[::-1]] # [ ... ]에 해당하는 코드

 

최종적으로 연산 3의 최종 처리 코드는 다음과 같다.

[[row[i] for row in arr[::-1]] for i in range(len(arr[0]))]

 

  • 연산 5, 6하기 전에, 먼저 하나의 배열을 그룹별로 4개로 쪼개자.

연산 5와 6에서 사용되므로, 따로 get_groups()라는 함수를 구현한다.

 

함수 내에서는 우선 4개의 배열을 구하기 위해 범위를 설정한다. 순서는 1번 그룹에서부터 4번 그룹순이며, 시작 위치(좌측 상단)와 끝 위치(우측 하단)의 위치를 담는다.

    rc = [
        [(0, 0), (n // 2, m // 2)], [(0, m // 2), (n // 2, m)],
        [(n // 2, m // 2), (n, m)], [(n // 2, 0), (n, m // 2)]
    ]

위 범위 배열을 순회하면서 기존 배열에서 각 그룹별로 배열을 추출하여 결과 리스트에 담는다. 결과 리스트의 첫 번째 원소엔 1번 그룹 배열이, 두 번째 원소엔 2번 그룹 배열, 세 번째 원소엔 3번 그룹 배열, 네 번째 원소엔 4번 그룹 배열이 들어가며, 함수는 그 결과를 반환한다.

 

  • 연산 5, 6에서는 zip 내장 함수를 활용하자.

연산 5을 예시로 살펴보자.

현재 그룹은 빨간색, 노란색, 파란색, 초록색 총 4개의 그룹으로 나뉘어져 있다. 새 배열에서는 0행에는 각 4번 그룹 배열의 0행과 1번 그룹 배열의 0행이 들어간다. 1행에는 4번 그룹 배열의 1행과 1번 그룹 배열의 1행이 들어가며, 2행 역시 마찬가지이다. 새 배열의 3행에는 이제 3번 그룹 배열의 0행과 2번 그룹 배열의 0행부터 쭉 들어간다.

result = []
for four, one in zip(groups[-1], groups[0]):
    result.append(four + one)

for three, two in zip(groups[-2], groups[1]):
    result.append(three + two)

따라서 위 코드처럼 4번 그룹 배열과 1번 그룹 배열을 zip으로 처리하고, 3번 그룹 배열과 2번 그룹 배열을 zip으로 처리하면 쉽게 최종 배열 result를 생성할 수 있다.

 

 

 

2. 정답 코드

import sys

input = sys.stdin.readline


def cmd1_upside_down(arr):
    return arr[::-1]


def cmd2_switch_sides(arr):
    return [row[::-1] for row in arr]


def cmd3_rotate_90_to_the_right(arr):
    return [[row[i] for row in arr[::-1]] for i in range(len(arr[0]))]


def cmd4_rotate_90_to_the_left(arr):
    return [[row[i] for row in arr] for i in range(len(arr[0]) - 1, -1, -1)]


def cmd5_rotate_group_clockwise(arr):
    groups = get_groups(arr)

    result = []
    for four, one in zip(groups[-1], groups[0]):
        result.append(four + one)

    for three, two in zip(groups[-2], groups[1]):
        result.append(three + two)

    return result


def cmd6_rotate_group_counterclockwise(arr):
    groups = get_groups(arr)

    result = []
    for two, three in zip(groups[1], groups[-2]):
        result.append(two + three)

    for one, four in zip(groups[0], groups[-1]):
        result.append(one + four)

    return result


def get_groups(arr):
    n, m = len(arr), len(arr[0])

    rc = [
        [(0, 0), (n // 2, m // 2)], [(0, m // 2), (n // 2, m)],
        [(n // 2, m // 2), (n, m)], [(n // 2, 0), (n, m // 2)]
    ]

    groups = []
    for start, end in rc:
        groups.append(list(
            [arr[i][j] for j in range(start[1], end[1])] for i in range(start[0], end[0])
        ))

    return groups


# main
n, m, r = map(int, input().split())
array = [list(map(int, input().split())) for _ in range(n)]
command = list(map(int, input().split()))

for cmd in command:
    if cmd == 1:
        array = cmd1_upside_down(array)
    elif cmd == 2:
        array = cmd2_switch_sides(array)
    elif cmd == 3:
        array = cmd3_rotate_90_to_the_right(array)
    elif cmd == 4:
        array = cmd4_rotate_90_to_the_left(array)
    elif cmd == 5:
        array = cmd5_rotate_group_clockwise(array)
    elif cmd == 6:
        array = cmd6_rotate_group_counterclockwise(array)

for row in array:
    print(" ".join(list(map(str, row))))
728x90