17470: 배열 돌리기 5

ewillwin·2023년 6월 21일
0

Problem Solving (BOJ)

목록 보기
82/230

  • 첫 플래티넘 문제/ 배열 돌리기 3번과 달리 이 문제는 R이 2000000이기 때문에 새로운 아이디어가 필요함

전반적인 구현 흐름

  • 우선 기존 arr를 1, 2, 3, 4 부분으로 나누어 origin_arr에 저장함
  • status_updown, status_leftright, status_rotate (순서대로 각 origin_arr의 상하반전, 좌우반전, 회전 상태를 나타냄)를 이용하여 각 origin_arr의 상태를 갱신함
  • mini_arr는 기존 arr의 mini 버전임. [[0, 1], [2, 3]] 형태로 구성돼있음
  • cmds의 cmd를 모두 실행시켜주어 mini_arr를 변경해주고, 그 과정에서 갱신된 status 변수들을 기반으로 상하반전, 좌우반전, 회전 상태를 orgin_arr에 적용해줌
  • final_arr에 mini_arr, origin_arr의 변경 상태를 최종적으로 저장해줌
  • 이런식으로 구현을 해줌으로써 R번의 연산 동안 크기가 작은 mini_arr만 변경시켜주고 마지막에만 mini_arr, origin_arr의 변경상태를 final_arr에 저장해줌으로써 시간 단축을 할 수 있음

cmd_1()

  • 상하반전 연산
  • 만약 배열이 90도 회전된 상태 (status_rotate % 2가 1인 경우)라면 origin_arr 기준으로 봤을 때, 상하반전이 좌우반전이 되고 좌우반전이 상하반전이 됨
    -> 배열이 90도 (또는 270도) 회전된 상태라면 status_leftright를 toggle해줌
    -> 그렇지 않다면 status_updown을 toggle해줌
  • mini_arr[0], mini_arr[1] = mini_arr[1], mini_arr[0]를 통해 mini_arr에서 상하반전 수행

cmd_2()

  • 좌우반전 연산
  • 만약 배열이 90도 회전된 상태 (status_rotate % 2가 1인 경우)라면 origin_arr 기준으로 봤을 때, 상하반전이 좌우반전이 되고 좌우반전이 상하반전이 됨
    -> 배열이 90도 (또는 270도) 회전된 상태라면 status_updown를 toggle해줌
    -> 그렇지 않다면 status_leftright을 toggle해줌
  • mini_arr[0][1], mini_arr[0][0] = mini_arr[0][0], mini_arr[0][1]; mini_arr[1][1], mini_arr[1][0] = mini_arr[1][0], mini_arr[1][1]를 통해 mini_arr에서 좌우반전 수행

cmd_3()

  • 오른쪽으로 90도 회전 연산
  • status_rotate = (status_rotate + 1) % 4를 수행하여 status 변수 갱신
  • cmd_5() 호출

cmd_4()

  • 왼족으로 90도 회전 연산
  • status_rotate = (status_rotate - 1) % 4 (참고로 (-1) % 4는 3임)을 수행하여 status 변수 갱신
  • cmd_6() 호출

cmd_5()

  • 1->2, 2->4, 3->1, 4->3 연산 (mini_arr 기준으로 보면 오른쪽으로 90도 회전 연산임)

cmd_6()

  • 1->3, 2->1, 3->4, 4->2 연산 (mini_arr 기준으로 보면 왼쪽으로 90도 회전 연산임)

rotation(src_arr)

  • origin_arr의 원소를 회전해줌
  • origin_arr별 오른쪽으로 90도 회전 연산

Source Code

import sys
from collections import deque

def cmd_1(): #상하반전
	global status_updown; global status_leftright; global status_rotate
	if status_rotate % 2: #배열이 90도 회전된 상태면 origin_arr 기준으로 봤을 때, 상하반전이 좌우반전이 되고 좌우반전이 상하반전이 됨
		status_leftright = not status_leftright
	else:
		status_updown = not status_updown

	mini_arr[0], mini_arr[1] = mini_arr[1], mini_arr[0]

def cmd_2(): #좌우반전
	global status_updown; global status_leftright; global status_rotate
	if status_rotate % 2: #배열이 90도 회전된 상태면 origin_arr 기준으로 봤을 때, 상하반전이 좌우반전이 되고 좌우반전이 상하반전이 됨
		status_updown = not status_updown
	else:
		status_leftright = not status_leftright

	mini_arr[0][1], mini_arr[0][0] = mini_arr[0][0], mini_arr[0][1]
	mini_arr[1][1], mini_arr[1][0] = mini_arr[1][0], mini_arr[1][1]

def cmd_3(): #오른쪽으로 90도 회전
	global status_rotate
	status_rotate = (status_rotate + 1) % 4
	cmd_5()

def cmd_4(): #왼족으로 90도 회전
	global status_rotate
	status_rotate = (status_rotate - 1) % 4 # -1 % 4 = 3임
	cmd_6()

def cmd_5(): #1->2, 2->4, 3->1, 4->3
	global mini_arr
	tmp_mini_arr = [[0, 0], [0, 0]]
	tmp_mini_arr[0][0] = mini_arr[1][0]
	tmp_mini_arr[0][1] = mini_arr[0][0]
	tmp_mini_arr[1][0] = mini_arr[1][1]
	tmp_mini_arr[1][1] = mini_arr[0][1]
	mini_arr = tmp_mini_arr

def cmd_6(): #1->3, 2->1, 3->4, 4->2
	global mini_arr
	tmp_mini_arr = [[0, 0], [0, 0]]
	tmp_mini_arr[0][0] = mini_arr[0][1]
	tmp_mini_arr[0][1] = mini_arr[1][1]
	tmp_mini_arr[1][0] = mini_arr[0][0]
	tmp_mini_arr[1][1] = mini_arr[1][0]
	mini_arr = tmp_mini_arr

def rotation(src_arr): #origin_arr를 회전
	dest_arr = [[0 for _ in range(len(src_arr))] for __ in range(len(src_arr[0]))] #회전하면 행개수와 열개수가 swap됨
	for i in range(len(src_arr[0])):
		for j in range(len(src_arr)):
			dest_arr[i][j] = src_arr[len(src_arr) - j - 1][i]
	return dest_arr


N, M, R = map(int, sys.stdin.readline()[:-1].split()) #N, M은 짝수/ N은 행개수, M은 열개수
arr = []
for n in range(N):
	arr.append(list(sys.stdin.readline()[:-1].split()))
cmds = list(map(int, sys.stdin.readline()[:-1].split()))

#기존 arr를 1, 2, 3, 4 구간으로 나누어 origin_arr에 할당
origin_arr = []
one = arr[:N//2]; two = arr[:N//2]; three = arr[N//2:]; four = arr[N//2:]
for i in range(N//2):
	two[i] = deque(two[i]); four[i] = deque(four[i])
	for _ in range(M//2):
		one[i].pop(); two[i].popleft(); three[i].pop(); four[i].popleft()
	two[i] = list(two[i]); four[i] = list(four[i])
origin_arr.append(one); origin_arr.append(two); origin_arr.append(three); origin_arr.append(four)

mini_arr = [[0, 1], [2, 3]] #origin_arr를 mini_arr로 표현
status_updown = False; status_leftright = False; status_rotate = 0 #각 origin_arr의 반전, 회전 상태를 나타냄
for cmd in cmds:
	if cmd == 1:
		cmd_1()
	elif cmd == 2:
		cmd_2()
	elif cmd == 3:
		cmd_3()
	elif cmd == 4:
		cmd_4()
	elif cmd == 5:
		cmd_5()
	elif cmd == 6:
		cmd_6()

if status_updown: #각 origin_arr별 상하반전 상태 적용
	for i in range(4):
		origin_arr[i].reverse()

if status_leftright: #각 origin_arr별 좌우반전 상태 적용
	for i in range(4):
		for j in range(len(origin_arr[i])):
			origin_arr[i][j].reverse()

for _ in range(status_rotate): #각 origin_arr별 회전 상태 적용
	for i in range(4):
		origin_arr[i] = rotation(origin_arr[i])

final_arr = []
final_arr.extend(origin_arr[mini_arr[0][0]])
final_arr.extend(origin_arr[mini_arr[1][0]])
for i in range(len(final_arr) // 2):
	final_arr[i].extend(origin_arr[mini_arr[0][1]][i])
	final_arr[i + len(final_arr) // 2].extend(origin_arr[mini_arr[1][1]][i])

for i in range(len(final_arr)):
	print(" ".join(final_arr[i]))
profile
Software Engineer @ LG Electronics

0개의 댓글