본문 바로가기

알고리즘/🥇 골드

백준 14891 톱니바퀴 파이썬 풀이

728x90

풀이일 : 2503237

난이도 : 골드5

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


문제

문제 생략 사진입니다.


아이디어

1. 각 톱니바퀴 12시 방향을 포인터로 사용

 

# 회전
모든 접점을 확인 후 한번에 회전
반시계 방향이면 포인터 + 1, 시계 방향 회전이면 포인터 + 7

# 점수 계산
1, 2, 3, 4 번 톱니바퀴의 포인터가 1이면 각 2^0 ~ 2^3


전체 풀이 코드

import sys


def spin(x, y): # 회전 여부 판단, 기록
    if x < 0 or y > 3: # 톱니바퀴 존재 확인
        return
    # 왼쪽 톱니바퀴의 3시 방향과 오른쪽 톱니바퀴의 9시 방향 극 비교
    # 같은 극일 경우
    if cogwheels[x][(pointers[x] + 2) % 8] == cogwheels[y][(pointers[y] + 6) % 8]:
        return
    # 다른 극을 경우, 이전에 움직이지 않은 톱니바퀴의 회전 방향 기록
    else:
        if check[y]:
            check[x] = check[y] * - 1
            spin(x - 1, x)
        else:
            check[y] = check[x] * - 1
            spin(y, y + 1)

    return


# 입력 받기
cogwheels = [sys.stdin.readline().strip() for _ in range(4)] # 톱니바퀴 극 정보
K = int(sys.stdin.readline())
pointers = [0, 0, 0, 0] # 각 톱니바퀴의 포인터
score = 0

for _ in range(K):
    num, direction = map(int, sys.stdin.readline().split())
    check = [0, 0, 0, 0] # 회전 여부 및 방향 기록
    check[num - 1] = 1 if direction < 0 else -1
    # 회전할 톱니바퀴 양쪽 톱니바퀴 회전여부 판단
    spin(num - 2, num - 1)
    spin(num - 1, num)

    for i in range(4): # 회전시키기
        pointers[i] += check[i] if check[i] >= 0 else 7
        pointers[i] = pointers[i] % 8

# 최종 결과 포인터 1이면 점수 획득
for i in range(4):
    if cogwheels[i][pointers[i]] == '1':
        score += 2 ** i

print(score)

상세 풀이 코드

def spin(x, y): # 회전 여부 판단, 기록
    if x < 0 or y > 3: # 톱니바퀴 존재 확인
        return
    # 왼쪽 톱니바퀴의 3시 방향과 오른쪽 톱니바퀴의 9시 방향 극 비교
    # 같은 극일 경우
    if cogwheels[x][(pointers[x] + 2) % 8] == cogwheels[y][(pointers[y] + 6) % 8]:
        return
    # 다른 극을 경우, 이전에 움직이지 않은 톱니바퀴의 회전 방향 기록
    else:
        if check[y]:
            check[x] = check[y] * - 1
            spin(x - 1, x)
        else:
            check[y] = check[x] * - 1
            spin(y, y + 1)

    return
  • 항상 왼쪽 톱니바퀴는 x로, 오른쪽 톱니바퀴는 y로 담아 함수를 호출한다.
  • 톱니바퀴는 총 4개로, 0 ~ 3 인덱스를 사용한다. x가 0보다 작거나, y가 3보다 크게 주어지는 경우에는 함수를 종료한다.
  • x 톱니바퀴의 3시 방향 극은 포인터(12시 방향)을 기준으로 +2를 8로 나눈 나머지 인덱스, y 톱니바퀴의 9시 방향 극은 포인터를 기준으로 +6을 8로 나눈 인덱스로 구해 두 인덱스의 극을 비교한다.
  • 비교 결과가 같다면, 다음 톱니바퀴는 회전하지 않으므로 함수를 종료한다.
  • 비교 결과가 다르다면, 이전에 회전한 톱니바퀴의 회전 방향과 반대를 표시해준다.

 

# 입력 받기
cogwheels = [sys.stdin.readline().strip() for _ in range(4)] # 톱니바퀴 극 정보
K = int(sys.stdin.readline())
pointers = [0, 0, 0, 0] # 각 톱니바퀴의 포인터
score = 0
  • cogwheels : 톱니바퀴들의 극 정보를 기록한다. 모든 톱니바퀴는 한 배열로 관리하여 인덱스로 접근한다.
  • pointers : 각 톱니바퀴들의 12시 방향을 기록한다. 톱니바퀴 회전 시 반시계 방향은 + 1, 시계 방향은 + 6해서 12시 방향을 추적한다.

 

for _ in range(K):
    num, direction = map(int, sys.stdin.readline().split())
    check = [0, 0, 0, 0] # 회전 여부 및 방향 기록
    check[num - 1] = 1 if direction < 0 else -1
    # 회전할 톱니바퀴 양쪽 톱니바퀴 회전여부 판단
    spin(num - 2, num - 1)
    spin(num - 1, num)

    for i in range(4): # 회전시키기
        pointers[i] += check[i] if check[i] >= 0 else 7
        pointers[i] = pointers[i] % 8
  • 회전할 톱니바퀴와 방향을 입력 받아 저장한다.
  • check : 회전 여부 및 방향을 기록한다. 회전 편의를 위해 반시계 방향은 1, 시계 방향은 -1로 기록한다.
  • 최초 회전한 톱니바퀴의 양쪽 톱니바퀴의 회전 여부를 확인하는 함수를 호출한다.
  • 반복문을 수행하며, check 내용을 pointers에 반영해 톱니바퀴를 회전한다.

 

# 최종 결과 포인터 1이면 점수 획득
for i in range(4):
    if cogwheels[i][pointers[i]] == '1':
        score += 2 ** i

print(score)
  • 모든 회전이 끝난 후, 각 톱니바퀴의 12시 방향 극을 확인하여, S극이라면 2의 톱니바퀴 인덱스 승만큼 점수를 더한다.

느낀점

  • 문자열을 입력받을 때, 개행문자를 어떻게 없애는 지 기억나지 않아서 조금 헤맸다.
  • 어렵지 않은 구현문제인데, 인덱스 설정이랑 회전 기록 등등 생각보다 오래 시간쓰고 풀어내서 알고리즘 열심히 해야겠다고 다시 다짐해본다.