코딩테스트/BOJ

[SWEA] [DFS] 4013. 특이한 자석

박소민 2023. 4. 9. 23:46
4013. 특이한 자석
 

SW Expert Academy

SW 프로그래밍 역량 강화에 도움이 되는 다양한 학습 컨텐츠를 확인하세요!

swexpertacademy.com

 

 

 

  • 내 풀이
    • 점수기준값인 point값을 수정해가면서 진행
    • 시계방향일때 point는 왼쪽으로 작아지고, 반시계방향일때는 오른쪽으로 커지도록 함 (처음에 헷갈려서 반대로함 주의)
    • 옆에 자석이랑 비교할때 현재 point값을 위에서 바꿔주기 때문에 기존의 point값을 저장해두고 그 위치기준으로 비교해야함
    • 현재 자석을 돌리면서 그 다음자석이 돌려진 후에, 다시 현재자석을 또 돌리지 못하도록 visited처리 해줘야함
#SW 4013
#4개 자석 k번 돌린 전부 돌린 후 점수
# 점수: n극 0점, s극 2의 자석번호 제곱수만큼1,2,4,8(0~3 제곱)
#시계방향 1 반시계방향 -1
#n극 0 s극 1
def point_check(pnt): #접하는 지점 
    if pnt-2<0:
        pnt+=8
    return pnt-2

def rotate(m,dir):
    visited[m]=True
    p=point[m] #기존 포인트값
    if dir==1: #시계방향일때 왼쪽으로(작아짐)
        if point[m]==0:
            point[m]=7
        else:
            point[m]-=1

        #접하는 면이 자석이 반대일때만 실행
        #위에서 point바뀌기 전값으로 생각해야함
        if m+1<=3 and magnet[m][(p+2)%8] != magnet[m+1][point_check(point[m+1])]: #우측 자석
            if visited[m+1]==False:
                rotate(m+1, -1)
        if m-1>=0 and magnet[m][point_check(p)]!=magnet[m-1][(point[m-1]+2)%8]:
            if visited[m-1]==False:#좌측 자석
                rotate(m-1,-1)
      
    else: #반시계방향일때 오른쪽으로(커짐)
        point[m]=(point[m]+1)%8
        
        #자석 반대면 실행
        if m+1<=3 and magnet[m][(p+2)%8]!=magnet[m+1][point_check(point[m+1])]: 
            if visited[m+1]==False:
                rotate(m+1, 1)
        if m-1>=0 and magnet[m][point_check(p)]!=magnet[m-1][(point[m-1]+2)%8]:
            if visited[m-1]==False:
                rotate(m-1,1)

T=int(input())
for tc in range(1,T+1):
    k=int(input())
    magnet=[]
    for i in range(4):
        #magnet[0] 위치가 점수계산할 위치
        magnet.append(list(map(int,input().split())))
  
    rotation=[]
    for j in range(k):
        #자석번호, 회전방향 [a,b]
        a,b=map(int,input().split())
        a-=1 #0~3번 자석으로 인덱스=이름 맞추기
        rotation.append([a,b])
  
    point=[0]*4 #점수위치
  
    #회전
    for rt in rotation:
        visited=[False]*4
        m,dir=rt #자석번호, 방향
        rotate(m,dir)
    
    result=0
    for idx, p in enumerate(point):
        if magnet[idx][p]==0: continue #n극 0점
        else: 
            result+=2**idx
  
    print(f'#{tc} {result}')

 

 

백준 14891이랑 같은문제
 

14891번: 톱니바퀴

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

www.acmicpc.net

  • 다른 사람 풀이
    • 시계, 반시계방향으로 회전 시키기위해 양 끝에서 값을 뺄 수있는 deque이용 
      • 딕셔너리를 이용해서 deque()을 value로 넣고 gears[key][value] 로 호출함
      • 회전을 deque. rotate() 함수 이용
    • 왼쪽방향 탐색할때는 계속 왼쪽방향만, 오른쪽 방향탐색때는 계속오른쪽만 탐색하기때문에 visited 필요없음
    • 기준 톱니바퀴가 있을 때, 왼쪽과 맞닿는 지점은 idx 2, 오른쪽은 6 !!! (내가 완전 복잡하게 처리한 부분)
deque.rotate()
import sys
from collections import deque

input=sys.stdin.readline
# 문제의 경우 1은 시계방향, -1은 반시계 방향이다.
# deque의 rotate = -1일 경우 반시계 방향, 1일 경우 시계 방향으로 움직인다.

def check_right(start, dirs):
    # 더 이상 조사가 불가능한 경우
    if start > 4 or gears[start-1][2] == gears[start][6]:
        return

    #계속 오른쪽 탐색
    check_right(start + 1, -dirs)
    #회전
    gears[start].rotate(dirs)


def check_left(start, dirs):
    if start < 1 or gears[start][2] == gears[start+1][6]:
        return
    
    check_left(start - 1, -dirs)
    gears[start].rotate(dirs)
        


gears = {}
# 기준 톱니바퀴가 있을 때, 왼쪽과 맞닿는 지점은 idx 2, 오른쪽은 6이다.
for i in range(1, 5):
    gears[i] = deque(map(int, list(input().rstrip())))
n = int(input())


for _ in range(n):
    num, dirs = map(int, input().split())

    # 기준 톱니바퀴가 주어졌을 때, 오른쪽 / 왼쪽이 회전 가능한지를 각각 확인하고 회전시킨다.
    check_right(num+1, -dirs)
    check_left(num-1, -dirs)
    # 기준 톱니바퀴를 회전시킨다.
    gears[num].rotate(dirs)
    

result = 0
for i in range(4):
    result += (2**i) * gears[i+1][0] #n극이라 0이면 곱해서 0 되므로
print(result)

이렇게 간결할 수가.........끄악