꺼내먹는지식 준

SW Expert Academy 6109 문제 (행렬회전) 본문

코딩테스트총정리/구현

SW Expert Academy 6109 문제 (행렬회전)

알 수 없는 사용자 2022. 1. 24. 21:34

SW Expert Academy 6109 문제. 추억의 2048게임 


문제링크: https://swexpertacademy.com/main/code/problem/problemDetail.do?contestProbId=AWbrg9uabZsDFAWQ


문제


입력: 

각 테스트 케이스의 첫 번째 줄에는 하나의 정수 N(1≤N≤20)과 하나의 문자열 S가 공백 하나로 구분되어 주어진다. S는 “left”, “right”, “up”, “down”의 넷 중 하나의 값이 주어지며, 각각 타일들을 왼쪽, 오른쪽, 위쪽, 아래쪽으로 이동시킨다는 뜻이다. 다음 N개의 줄의 i번째 줄에는 N개의 정수가 공백 하나로 구분되어 주어진다. 이 정수들은 0이거나 2이상 1024이하의 2의 제곱수들이다. i번째 줄의 j번째 정수는 격자의 위에서 i번째 줄의 왼쪽에서 j번째에 있는 칸에 있는 타일에 어떤 정수가 적혀 있는지 나타내며, 0이면 이 칸에 타일이 없음을 의미한다.

 

출력:

각 테스트 케이스마다 ‘#t’(t는 테스트케이스 번호를 의미하며 1부터 시작한다)를 출력하고 한 줄을 띄운 후, N줄에 걸쳐 격자의 어떤 위치에 어떤 숫자가 적힌 타일이 있는지 입력 형식과 같은 형식으로 출력한다.

 

예시


입력:

2
5 up
4 8 2 4 0
4 4 2 0 8
8 0 2 4 4
2 2 2 2 8
0 2 2 0 0
2 down
16 2
0 2

출력:

#1
8 8 4 8 8
8 4 4 2 4
2 4 2 0 8
0 0 0 0 0
0 0 0 0 0
#2
0 0
16 4

 

풀이


단순 구현 문제

다만, right, left, up, down 을 한번에 처리해주기 위해서 회전행렬 개념을 정리한다. 

 

회전행렬이란, 아래 그림과 같이 말그대로 행렬을 회전시키는 것이다. 

좌표값 위치 변화에 맞춰 값의 위치가 이동한다. 

 

90도 회전

 

모든 문제가 그렇듯, 잘 살펴보면 규칙이 보인다. 

 

\[ [y,x] \rightarrow [x, N-1-y] \]

[0,0] $\rightarrow$ [0,2] 

[0,1] $\rightarrow$  [1,2] 

[0,2] $\rightarrow$ [2,2] 

 

0 $\rightarrow$  2, 1  $\rightarrow$  1 , 2 $\rightarrow$  0  $: N -1 - y $

 

180도 회전

 

마찬가지로 규칙이 존재한다. 

\[ [y,x] \rightarrow [N-1-y  ,N-1-x]  \]

 

[0,0] $\rightarrow$ [2,2]

[0,1] $\rightarrow$  [2,1] 

[0,2] $\rightarrow$ [2,0] 

 

 

해당 문제에서 요구하는 회전 행렬은 다음의 3경우이다.

 

1) left $\rightarrow$ right

 

\[  [y,x] \rightarrow [y ,N-1-x] \]

2) left $\rightarrow$ up

\[  [y,x] \rightarrow [x,y] \]

3)left $\rightarrow$ down

\[  [y,x] \rightarrow [N-1-x, y] \]

 

def game(value):
    global line 
    global stack 
    if value != 0:
        if len(stack) == 0:
            stack.append(value)
        else:
            if stack[-1] == value:
                stack[-1] += value
                line += stack 
                stack = []       
            else:
                stack.append(value)
        


T = int(input())


for test_case in range(1, T + 1):

    n, direction = input().split()

    n = int(n)

    data = [None] * n

    for i in range(n):
        data[i] = list(map(int, input().split()))

    f_data = [[0] * n for _ in range(n)]


    if direction == "left":
        for i in range(n):
            stack = []
            line = []
            for j in range(n): 
                game(data[i][j])  
            line += stack
            for k in range(len(line)):
                f_data[i][k] = line[k] 

    elif direction == "right":
        for i in range(n):
            stack = []
            line = []
            for j in range(n):
                game(data[i][n-1-j])
            line += stack
            for k in range(len(line)):
                f_data[i][n-1-k] = line[k] 

    elif direction == "up":
        for i in range(n):
            stack = []
            line = []
            for j in range(n):
                game(data[j][i])
            line += stack
            for k in range(len(line)):
                f_data[k][i] = line[k] 

    elif direction == "down":
        for i in range(n):
            stack = []
            line = []
            for j in range(n):
                game(data[n-1-j][i])
            line += stack
            for k in range(len(line)):
                f_data[n-1-k][i] = line[k] 


    for i in range(n):
        print(' '.join(map( str, f_data[i])))

 

하지만 파이썬의 특징을 이용해서 회전 행렬을 쉽게 구현할 수 있다. 

lst = [[1,2,3],[4,5,6],[7,8,9]]
list(zip(*lst[::-1] ))

출력

[(7, 4, 1), (8, 5, 2), (9, 6, 3)]

살펴보자면 먼저 [::-1] 로 리스트 원소의 순서를 바꾼다. 

[[7,8,9], [4,5,6], [1,2,3]]

그 후, * 로 unpacking 하고 zip 으로 묶어준다. 즉 

zip([7,8,9], [4,5,6], [1,2,3]) 이 되고 list 를 취해준다. 

 

결과적으로 

[[7,4,1], [8,5,2], [9,6,3]]

으로 90도 회전된다. 필요한 각도에 따라 회전을 시켜주면 된다. 

 

 

Comments