- 문제 : https://www.acmicpc.net/problem/15662

 

문제 이해 

- 전체 T개의 톱니바퀴가 주어지고, 각각의 톱니바퀴의 각 바퀴 칸에는 N극 또는 S극이 있다. 

 

 

- 문제에서 특정 톱니바퀴가 돌면 옆에 있는 톱니바퀴는 움직이는 톱니바퀴와 맞닿아 있는 부분이 어떤지에 따라 움직일 수도 있고, 아닐 수도 있다. 

    - 맞닿아 있는 부분이 S극 - N극, N극 - S극 인 경우는 맞닿아 있는 톱니바퀴도 움직인다.

    - 이때 주의해야할 건 기존 톱니바퀴 방향과는 반대로 회전한다는 것이다. 기존 톱니바퀴가 시계방향(direction = 1)으로 돈다면, 맞닿아 있는 톱니바퀴는 반시계 방향(direction = -1)로 돈다. 반대 방향도 마찬가지이다. 

    - 기준 톱니바퀴의 오른쪽으로 맞닿은 톱니바퀴의 정확한 칸 위치는 10시 방향(인덱스 6 또는 -2) 바퀴이고, 왼쪽으로 맞닿은 톱니바퀴는 2시 방향(인덱스 2)이다. 

 

 

- 위에서 주어진 조건대로 맞닿아 있는 바퀴의 위치도 정해져 있고, 극이 다를 경우 서로 반대로 회전하는 것까지 알 수 있다. 하지만 내가 막혔던 부분은 하나의 바퀴가 돌 때 오른쪽 혹은 왼쪽으로 계속 회전할텐데 그거를 queue로 해야하나 싶었는데 어떻게 구현해야하는지 몰랐다. 

    - 풀이를 찾아보니 문제에서 회전하는 톱니바퀴가 주어졌을 때, 그 톱니바퀴를 기준으로 오른쪽과 왼쪽 각각 for문으로 진행하면서 돌아가는 조건을 만족하는 톱니바퀴를 모두 배열에 넣은 다음에 한번에 모두 둘리면 된다. 만약 극이 같은 게 나오면 그즉시 종료된다. 

        # t 기준 오른쪽 기어
        for i in range(t+1, T+1):
            if gears[i][-2] != gears[i-1][2]: 
            	turnElement.append(i)
            else: 
            	break
                
        # t 기준 왼쪽 기어
        for i in range(t-1, 0, -1):
            if gears[i][2] != gears[i+1][-2]: 
            	turnElement.append(i)
            else: 
            	break

 

   

    - 톱니바퀴가 돌아가는 것은 각각의 인덱스가 오른쪽, 왼쪽으로 한칸씩 이동하는 것이므로 deque의 rotate를 이용하면 쉽다. 

    - 그리고 그때 기준이 되는 톱니바퀴(t)의 바로 양옆에 있는 것은 반대로 돌지만, 그게 아닌 한칸 떨어진 것들은 모두 톱니바퀴 t와 같은 방향으로 돈다. (이부분 생각하기!)

        # t 기어 회전
        gears[t].rotate(direction)
        
        # t 기어와 맞닿은 극이 다른 기어 회전
        for element in turnElement:
            if (element - t) % 2 != 0 :
                gears[element].rotate(-direction)
            else:
                gears[element].rotate(direction)

 

 

- 회전하는 톱니바퀴 인덱스와 회전 방향이 주어지는데, 이를 turn 배열에 넣은 뒤 반복문을 돌리면서 위 과정을 진행하면 된다.

 

 

- 모든 톱니바퀴가 돌았다면 마지막에는 각 톱니바퀴에서 0 인덱스 값이 1인 톱니바퀴의 개수를 구해서 출력하면된다. (더 편하게 하기 위해선 개수를 안 세도 되고, 값이 1이므로 톱니바퀴의 0인덱스 값을 모두 더한 값을 출력해도 된다)

    return sum([gears[i][0] for i in range(1, T+1)])

 

정답 풀이 

from collections import deque
import sys
input = sys.stdin.readline

def solution(T, gears, K, turn):
    for t, direction in turn:
        turnElement = []
        
        # t 기준 오른쪽 기어
        for i in range(t+1, T+1):
            if gears[i][-2] != gears[i-1][2]: 
            	turnElement.append(i)
            else: 
            	break
                
        # t 기준 왼쪽 기어
        for i in range(t-1, 0, -1):
            if gears[i][2] != gears[i+1][-2]: 
            	turnElement.append(i)
            else: 
            	break
                
        # t 기어 회전
        gears[t].rotate(direction)
        
        # t 기어와 맞닿은 극이 다른 기어 회전
        for element in turnElement:
            if (element - t) % 2 != 0 :
                gears[element].rotate(-direction)
            else:
                gears[element].rotate(direction)
            
    return sum([gears[i][0] for i in range(1, T+1)])

T = int(input())
gears = [0] + [deque(map(int,list(input().strip()))) for _ in range(T)]
K = int(input())
turn = [list(map(int, input().split())) for _ in range(K)]

res = solution(T, gears, K, turn)
print(res)

 

삽질한 코드,,,

wheels = []
t = int(input())
for _ in range(t):
    wheels.append(list(input()))

def move_straight(arr):
    temp = [arr[-1]]
    for i in range(len(arr) - 1):
        temp.append(arr[i])
    return temp 

def move_reverse(arr):
    temp = []
    for i in range(1, len(arr)):
        temp.append(arr[i])
    temp.append(arr[0])
    return temp
        
for _ in range(int(input())):
    number, direction = map(int, input().split())
    number -= 1
    
    if number == 0:
        if wheels[number][2] != wheels[number + 1][-2]:
            if direction == 1: # 시계방향이면 옆에는 반시계로
                wheels[number + 1] = move_reverse(wheels[number + 1])
            elif direction == -1:
                wheels[number + 1] = move_straight(wheels[number + 1])
    elif number == t - 1:
        if wheels[number][-2] != wheels[number - 1][2]:
            if direction == 1: # 시계방향이면 옆에는 반시계로
                wheels[number - 1] = move_reverse(wheels[number - 1])
            elif direction == -1:
                wheels[number - 1] = move_straight(wheels[number - 1])
    else:
        if wheels[number][2] != wheels[number + 1][-2]:
            if direction == 1:
                wheels[number + 1] = move_reverse(wheels[number + 1])
            elif direction == -1:
                wheels[number + 1] = move_straight(wheels[number + 1])
        if wheels[number][-2] != wheels[number - 1][2]:
            if direction == 1:
                wheels[number - 1] = move_reverse(wheels[number - 1])
            elif direction == -1:
                wheels[number - 1] = move_straight(wheels[number - 1])

answer = 0  
for wheel in wheels:
    if wheel[0] == '1':
        answer += 1
        
print(answer)

 

 

참고 블로그 

https://velog.io/@isayaksh/%EC%95%8C%EA%B3%A0%EB%A6%AC%EC%A6%98-BOJ-15662-%ED%86%B1%EB%8B%88%EB%B0%94%ED%80%B4-2-Python

- 문제 : https://www.acmicpc.net/problem/15686

 

문제 이해 

- 처음에 보고 bfs로 풀어야 하나 싶었는데, 탐색이 아니고 문제를 잘 이해하고 브루트 포스로 구현하면 되는 문제다. 

- 문제를 이해한 바로는 다음과 같다. 

    - 주어진 행렬의 값 중 1인 값을 house로, 2인 값을 chicken 배열에 저장한다. 

    - 문제에서 현재 존재하는 치킨집(행렬 값 2) 중에 임의로 m개를 뽑는다고 했으므로 combinations으로 chicken 좌표 중에 임의의 m개를 뽑는다. 

    - 임의로 뽑은 m개의 치킨집 각각의 좌표에 대해 각 집과의 최소 거리의 합을 구한다. m개의 치킨집 후보가 여러개 있으므로 각각마다의 치킨거리(집 ~ 치킨집 최소거리) 합의 최솟값을 구하면 그게 정답이다. 

- 주의할 점 

    - 주의해야할 거는 행렬은 n x n 크기의 행렬이고, m은 앞으로 선택한 치킨집의 개수이다. 처음에 행렬 크기를 n x m 으로 했다가 틀렸다! (house와 chicken 배열에 값을 원래 개수와 다르게 추가할 가능성이 있기 때문)

 

 

정답 풀이1 

내가 푼 풀이

from itertools import combinations

n, m = map(int, input().split())

chicken = []
house = []
for i in range(n):
    temp = list(map(int, input().split()))
    for j in range(n):
        if temp[j] == 2:
            chicken.append([i, j])
        if temp[j] == 1:
            house.append([i, j])

answer = 1e9
candidates = list(combinations(chicken, m))
for candidate in candidates:
    count = 0
    for x, y in house:
        temp = 1e9
        for i, j in candidate:
            temp = min(temp, abs(x - i) + abs(y - j))
        count += temp
    answer = min(answer, count)
        
print(answer)

 

정답 풀이2

각 치킨 거리를 구하는 것만 함수로 빼는 풀이가 있었는데 시간이 차이가 꽤 많이 난다. 뭔가 함수로 빼고 말고가 시간복잡도에 영향을 주는게 있는걸까..??

 

def get_sum(candidate):
    count = 0
    for x, y in house:
        temp = 1e9
        for i, j in candidate:
            temp = min(temp, abs(x - i) + abs(y - j))
        count += temp 
    return count

치킨집의 위치를 임의로 m개를 구한 candidate와 house를 반복문 돌리면서 각각의 최소 거리 합을 구하는 로직이다.

 

from itertools import combinations

n, m = map(int, input().split())

chicken = []
house = []
for i in range(n):
    temp = list(map(int, input().split()))
    for j in range(n):
        if temp[j] == 2:
            chicken.append([i, j])
        if temp[j] == 1:
            house.append([i, j])

def get_sum(candidate):
    count = 0
    for x, y in house:
        temp = 1e9
        for i, j in candidate:
            temp = min(temp, abs(x - i) + abs(y - j))
        count += temp 
    return count 

answer = 1e9
candidates = list(combinations(chicken, m))
for candidate in candidates:
    answer = min(answer, get_sum(candidate))
        
print(answer)

- 문제 : https://www.acmicpc.net/problem/7490

 

문제 이해 

- 1부터 n까지의 수를 오름차순으로 정렬한 뒤 그 사이에 '+', '-', ' '(공백)의 연산을 넣은 뒤 연산의 결과가 0인 수식들을 출력하는 문제다. 

- 브루트포스 알고리즘으로 주어진 1 - n 숫자 사이에 계속 연산들을 넣고, 그 중 결과로 식별하면 된다고 이해까지는 했는데, 구체적으로 어떻게 구현해야할지 몰랐다. 

- 풀이를 찾아보니 일단 연산을 추가하는 거는 재귀함수로 돌리면 되고, 그렇게 구한 연산들을 숫자와 나란히 붙인뒤 값을 식별해 출력하면 된다.

    - 재귀함수 돌리고 목표 연산 개수인 k개에 도달하면, operator_list에 array를 deepcopy해서 추가해줘야 한다. (꼭 deepcopy를 해 야한다)

    - 연산 추가하는 순서도 중요하다 아스키 코드가 작은 ' ' (아스키 코드 34), '+' (아스키 코드 44), '-' (아스키 코드 45) 순서로 해야 틀리지 않는다. 

- 이때 만든 수식의 결과 값이 0인지 확인해야하는데, 문자열이므로 eval() 함수를 이용해 문자열을 계산해 결과가 0임을 확인하면된다. 여기에서 중요한 게 ' '(공백)은 count 되면 안되므로 ' '를 ''로 대체해서 eval을 진행하면 된다. 

 

근데 아직도 문제가 잘 이해 안 가는게 수식의 합이 0이어야 하는데, 아래 수식 같은 경우는 어떻게 결과가 0이 되는지 모르겠다,,,

1-2 3-4 5+6 7

그래서 pythontutor로 결과를 돌려봤는데  1-2(공백)3 인 경우에는 1-23으로 계산이 된다. 

 

 

정답 풀이 

import copy

def recursive(array, k):
    if len(array) == k:
        operator_list.append(copy.deepcopy(array))
        return
    
    array.append(' ')
    recursive(array, k)
    array.pop()
    
    array.append('+')
    recursive(array, k)
    array.pop()
    
    array.append('-')
    recursive(array, k)
    array.pop()
    
    
t = int(input())
for _ in range(t):
    n = int(input())
    operator_list = []
    recursive([], n - 1)
    integer = [i for i in range(1, n + 1)]
    
    for operator in operator_list:
        string = ''
        for i in range(n - 1):
            string += str(integer[i]) + operator[i]     
        string += str(integer[-1])
        if eval(string.replace(' ', '')) == 0:
            print(string)
    print()

 

참고 블로그 : https://reliablecho-programming.tistory.com/104

- 문제 : https://www.acmicpc.net/problem/14719

 

문제 이해 

- 처음에는 예제만 적용해서 풀이를 작성했는데, 이는 범용적인 케이스를 고려하지 않았기에 틀렸다. 

- 그래서 풀이를 찾아보니 주어진 원소들을 하나씩 탐색하면서 i번째 원소의 왼쪽과 오른쪽 리스트에서 각각 최대값을 구한다. 

- 이 최대값 중 더 작은 값이 i번째 원소 높이가 낮아야 물이 고일 수 있다. 그래서 이 경우에만 높이 차이를 answer에 더해주면 된다. 

 

정답풀이 

h, w = map(int, input().split())
buildings = list(map(int, input().split()))

answer = 0
for i in range(1, w - 1):
    left_max = max(buildings[:i])
    right_max = max(buildings[i + 1:])
    
    compare = min(left_max, right_max)
    
    if buildings[i] < compare:
        answer += compare - buildings[i]
        
print(answer)

 

시도한 풀이 

같은 크기의 최대 높이가 2개 이상일 때 적용이 되지 않는다. 

h, w = map(int, input().split())
buildings = list(map(int, input().split()))

# 최대 높이를 기준으로 왼쪽, 오른쪽 나눠서 진행
# 양쪽 최대 높이 보다 한단계 작은 수가 높이가 되어서 물 채우면 됨
answer = 0
if buildings.count(0) <= w - 2:
    max_value = max(buildings)
    max_index = buildings.index(max_value)
    
    a = max(buildings[:max_index])
    for i in range(max_index):
        answer += a - buildings[i]
        
    if max_index + 1 < w and buildings[max_index + 1]:
        b = max(buildings[max_index + 1:])
        for i in range(max_index + 1, w):
            answer += b - buildings[i]
     
print(answer)

참고 블로그 : https://seongonion.tistory.com/115

+ Recent posts