프로그래머스 Lv.2: 다리를 지나는 트럭 - Python 풀이
문제 설명
프로그래머스
SW개발자를 위한 평가, 교육, 채용까지 Total Solution을 제공하는 개발자 성장을 위한 베이스캠프
programmers.co.kr
트럭 여러 대가 강을 가로지르는 일차선 다리를 정해진 순으로 건너려 합니다. 모든 트럭이 다리를 건너려면 최소 몇 초가 걸리는지 알아내야 합니다. 다리에는 트럭이 최대 bridge_length대 올라갈 수 있으며, 다리는 weight 이하까지의 무게를 견딜 수 있습니다. 단, 다리에 완전히 오르지 않은 트럭의 무게는 무시합니다.
예를 들어, 트럭 2대가 올라갈 수 있고 무게를 10kg까지 견디는 다리가 있습니다. 무게가 [7, 4, 5, 6]kg인 트럭이 순서대로 최단 시간 안에 다리를 건너려면 다음과 같이 건너야 합니다.
경과 시간 | 다리를 지난 트럭 | 다리를 건너는 트럭 | 대기 트럭 |
0 | [] | [] | [7,4,5,6] |
1~2 | [] | [7] | [4,5,6] |
3 | [7] | [4] | [5,6] |
4 | [7] | [4,5] | [6] |
5 | [7,4] | [5] | [6] |
6~7 | [7,4,5] | [6] | [] |
8 | [7,4,5,6] | [] | [] |
따라서, 모든 트럭이 다리를 지나려면 최소 8초가 걸립니다.
solution 함수의 매개변수로 다리에 올라갈 수 있는 트럭 수 bridge_length, 다리가 견딜 수 있는 무게 weight, 트럭 별 무게 truck_weights가 주어집니다. 이때 모든 트럭이 다리를 건너려면 최소 몇 초가 걸리는지 return 하도록 solution 함수를 완성하세요.
제한 조건
- bridge_length는 1 이상 10,000 이하입니다.
- weight는 1 이상 10,000 이하입니다.
- truck_weights의 길이는 1 이상 10,000 이하입니다.
- 모든 트럭의 무게는 1 이상 weight 이하입니다.
입출력 예
bridge_length | weight | truck_weights | return |
2 | 10 | [7,4,5,6] | 8 |
100 | 100 | [10] | 101 |
100 | 100 | [10,10,10,10,10,10,10,10,10,10] | 110 |
문제 요약) 다리가 길이 제한, 무게 제한이 있을 때 주어진 트럭이 모두 다 건넜을 때의 최소 시간을 구해라.
풀이 과정
처음에 삽질 하다가 싹 다 지우고 그냥 소요되는 시간별로 상태 그려보고 그대로 구현했더니 맞았습니다.
그려보고 나니 어떤 데이터를 가지고 있어야 할지 알 수 있었습니다. 일단 END 트럭은 필요 없으니 사용하지 않았습니다. PT와 ST 값이 모두 비어 있을 때에 반복을 종료하면 됩니다.
또 처음에는 그림처럼 다리 위의 트럭이 다 지나가면 없애기 위해서 RT(Remaining Time) 라는 배열로 남은 시간을 트래킹 하고자 했는데, 코드로 구현하다 보니 다리 위 트럭의 무게 배열 PT(Passing Trucks) 에서 트럭을 제거하느냐 마느냐가 RT에 달려 있습니다.
passing_trucks.append((start_trucks.popleft(), spending_time))
때문에 해당 값을 이렇게 하나로 가져갔습니다. 트럭의 무게와 해당 트럭이 다리를 다 지나가기 위해 남은 시간을 튜플로 만들어 리스트에 저장합니다.
전체 시간 T가 증가할 때마다 다리 위 트럭의 남은 시간은 -1이 되고, 0이 되면 리스트에서 제거합니다.
정답 코드
from collections import deque
def solution(bridge_length, weight, truck_weights):
# 문제의 설명이 불친절해서 변수 이름 바꿨습니다
# 한 트럭당 다리를 지날 때 걸리는 시간입니다
spending_time = bridge_length
# 이것도 저 보기 편하라고 바꿨습니다
# 첫번째 값을 빠르게 제거하기 위해 deque 사용
start_trucks = deque(truck_weights)
# (트럭 무게, 해당 트럭이 다리를 다 건너기까지 남은 시간) 형태의 튜플을 담을 리스트
passing_trucks = []
# 전체 소요 시간
time = 0
# 다리를 건너야 되는 트럭과 다리를 건너고 있는 트럭이 모두 없어지면 반복 종료
while start_trucks or passing_trucks:
# 시간은 갑니다
time += 1
# 다리 위의 트럭의 시간도 갑니다
# 0초가 되면 리스트에서 제거합니다
passing_trucks = [(w, t - 1) for w, t in passing_trucks if t - 1 != 0]
# 건너야 되는 트럭이 남았고, 다리가 여유 있어서 새 트럭이 더 올라올 수 있으면
if start_trucks and weight - sum(w for w, _ in passing_trucks) >= start_trucks[0]:
# 네 다음 트럭 올라오세요
passing_trucks.append((start_trucks.popleft(), spending_time))
return time
프로그래머스의 경우,
‘테스트 케이스 추가하기’
라는 버튼을 통해 직접 테스트 케이스를 추가할 수 있습니다.
저의 경우, 서치해서 나온 테스트 케이스들을 왕창 가져와서 추가해서 돌려 봤습니다만. 분명 LGTM하게 짰는데 딱 하나의 케이스(← 데이터 양도 많아서 손으로 테스트는 불가능했음)에서만 기댓값이 74인데 73이 나와서 틀렸다고 뜨길래 제가 뭘 놓친 줄 알았습니다. 그래서 1시간 동안 디버깅을 했지만 시간별로 트럭 들어오는 거 찍어 봐도 분명 다 맞거든요. 대체 왜 74라는 거지? 열 받네 하고 그냥 제출하기 눌렀는데 맞았습니다. 하하! 이상한 테스트 케이스였던 것 같습니다. ^^
오늘의 교훈: 인터넷의 정보를 과신하지 맙시다. 일단 들이박고 보는 것도 괜찮습니다.
이상입니다.