Uknow's Lab.
article thumbnail

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

 

14891번: 톱니바퀴

총 8개의 톱니를 가지고 있는 톱니바퀴 4개가 아래 그림과 같이 일렬로 놓여져 있다. 또, 톱니는 N극 또는 S극 중 하나를 나타내고 있다. 톱니바퀴에는 번호가 매겨져 있는데, 가장 왼쪽 톱니바퀴

www.acmicpc.net

 

난이도 : 골드 5
태그 : 구현, 시뮬레이션

 


1. 설명

구현 문제로써,  문제의 지문을 읽고 그대로 구현하여 풀었던 문제입니다.

 

 

각 톱니바퀴(gear라는 이름으로 변수명을 지었습니다) 는 LinkedList<Char>를 이용하여 구현하였고,

4개의 톱니가 존재하므로 길이가 4인 배열을 생성 및 초기화 하였습니다.

<code />
val gear = Array(4) { LinkedList<Char>() }

 

 

입력값 저장

<code />
for (i in 0 until 4) { readLine()!!.forEach { gear[i].add(it) } }

4개의 톱니(gear)에 입력값을 각각 저장합니다.

각 톱니는 링크드 리스트를 사용하여 12시 값 부터 시계 방향으로 총 8개의 값을 받으며,

오른쪽의 경우 리스트의 2번째 인덱스가, 왼쪽의 경우 리스트의 6번째 인덱스가 해당 값을 가지게 됩니다.

 

 

그림으로 표현하자면, 위와 같이 표현할 수 있습니다.

 

 


2. 각 톱니바퀴의 회전 처리

<code />
val n = readLine()!!.toInt() for (i in 0 until n) { val input = readLine()!!.split(" ") val gearIdx = input[0].toInt() - 1 val direction = input[1].toInt() // 1 : 시계방향, -1 : 반시계방향 val isRotate = arrayOf(false, false, false, false) val flags = arrayOf(0, 0, 0, 0) flags[gearIdx] = direction isRotate[gearIdx] = true for (j in gearIdx until 3) { if (gear[j][2] != gear[j + 1][6]) { isRotate[j + 1] = true flags[j + 1] = flags[j] * -1 } else { break } } for (j in gearIdx downTo 1) { if (gear[j][6] != gear[j - 1][2]) { isRotate[j - 1] = true flags[j - 1] = flags[j] * -1 } else { break } } for (j in 0 until 4) { if (isRotate[j]) { when (flags[j]) { 1 -> { gear[j].addFirst(gear[j].removeLast()) } -1 -> { gear[j].addLast(gear[j].removeFirst()) } } } } }

각 톱니바퀴의 회전을 처리하는 부분입니다. 하나씩 살펴보도록 하겠습니다.

 

 

 

 

<code />
val input = readLine()!!.split(" ") val gearIdx = input[0].toInt() - 1 val direction = input[1].toInt() // 1 : 시계방향, -1 : 반시계방향 val isRotate = arrayOf(false, false, false, false) val flags = arrayOf(0, 0, 0, 0) flags[gearIdx] = direction isRotate[gearIdx] = true

먼저, 사용되는 변수는 위와 같습니다.

 

gearIdx는 몇 번째 기어인지를,

direction은 방향을 담는 변수입니다. ( 1: 시계방향, -1: 반시계방향 )

 

isRotate는 회전이 되었는가를 담을 변수이며,

flags는 각 톱니바퀴가 회전하는 방향을 담을 변수입니다.

 

direction은 input값으로 받은 기어의 회전 방향을,

flags는 각 기어의 회전 방향을 담으니 혼동 없으시길 바랍니다.

 

 

<code />
for (j in gearIdx until 3) { if (gear[j][2] != gear[j + 1][6]) { isRotate[j + 1] = true flags[j + 1] = flags[j] * -1 } else { break } } for (j in gearIdx downTo 1) { if (gear[j][6] != gear[j - 1][2]) { isRotate[j - 1] = true flags[j - 1] = flags[j] * -1 } else { break } }

 

그 후, 선택된 기어를 기준으로 좌우 방향으로 반복문을 돌립니다.

 

오른쪽 방향으로는 현재 타겟 기어의 오른쪽(idx = 2)와 다음 타겟 기어의 왼쪽(idx = 6)을 비교하여

같은 극일땐 회전하지 않도록, 서로 다른 극일땐 회전하도록 isRotate 변수의 값을 조정합니다.

 

회전 방향을 담는 flags는 이전 기어의 반대 방향이니 -1을 곱하여 부호를 반대로 지정해주었습니다.

 

왼쪽 방향의 반복문도 오른쪽 방향의 반복문과 같습니다.

현재 타겟 기어의 왼쪽(idx = 6)과 다음 타겟 기어의 오른쪽(idx = 2)를 비교하여

같은 극일땐 회전하지 않도록, 다른 극일땐 회전하게끔 isRotate와 flags의 값을 조정합니다.

 

 

<code />
for (j in 0 until 4) { if (isRotate[j]) { when (flags[j]) { 1 -> { gear[j].addFirst(gear[j].removeLast()) } -1 -> { gear[j].addLast(gear[j].removeFirst()) } } } }

이후 회전이 될 기어(isRotate가 true)에 한하여 기어를 회전하면 됩니다.

 

리스트의 마지막 값을 빼서 처음에 두면 시계 방향으로,

리스트의 첫째 값을 빼서 마지막에 추가하면 반시계 방향으로 회전한 것 처럼 보이겠죠?

 

 

 

 

<code />
var score = 0 for (i in 0 until 4) { if (gear[i][0] == '1') score += (2.0.pow(i)).toInt() } println(score)

마지막으로 점수 계산입니다.

각 기어의 12시 값 (idx = 0)의 값이 N극 ( = '1) 일때 점수를 부여하면 되는데요.

<code />
1번 톱니바퀴의 12시방향이 N극이면 0점, S극이면 12번 톱니바퀴의 12시방향이 N극이면 0점, S극이면 23번 톱니바퀴의 12시방향이 N극이면 0점, S극이면 44번 톱니바퀴의 12시방향이 N극이면 0점, S극이면 8

 2의 idx 제곱이기에 2.0.pow(i)로 간단히 구할 수 있었습니다.

 

 


3. 후기

구현 / 시뮬레이션 태그 문제였던 만큼, 문제의 지문을 잘 읽고 그대로 구현하면 풀 수 있던 문제였던 것 같습니다.

코틀린으로 도전해보는 첫 골드 문제였는데, 실버에 비해 갑자기 급상승한듯한 난이도에 당황했다가,

천천히 지문을 잘 읽고 풀어보니 생각보다 할만했던 문제였습니다.

 

골드 4, 3, 2, 1 문제들이 벌써 두렵긴 하지만 열심히 공부하면 풀 수 있겠죠 허허....

profile

Uknow's Lab.

@유노 Uknow

인생은 Byte와 Double 사이 Char다. 아무말이나 해봤습니다.