문제
문제 설명
당신은 일렬로 나열된 n
개의 집에 택배를 배달하려 합니다. 배달할 물건은 모두 크기가 같은 재활용 택배 상자에 담아 배달하며, 배달을 다니면서 빈 재활용 택배 상자들을 수거하려 합니다. 배달할 택배들은 모두 재활용 택배 상자에 담겨서 물류창고에 보관되어 있고, i번째 집은 물류창고에서 거리 i
만큼 떨어져 있습니다. 또한 i
번째 집은 j
번째 집과 거리 j - i
만큼 떨어져 있습니다. (1 ≤ i
≤ j
≤ n
) 트럭에는 재활용 택배 상자를 최대 cap개 실을 수 있습니다. 트럭은 배달할 재활용 택배 상자들을 실어 물류창고에서 출발해 각 집에 배달하면서, 빈 재활용 택배 상자들을 수거해 물류창고에 내립니다. 각 집마다 배달할 재활용 택배 상자의 개수와 수거할 빈 재활용 택배 상자의 개수를 알고 있을 때, 트럭 하나로 모든 배달과 수거를 마치고 물류창고까지 돌아올 수 있는 최소 이동 거리를 구하려 합니다. 각 집에 배달 및 수거할 때, 원하는 개수만큼 택배를 배달 및 수거할 수 있습니다.
다음은 cap
=4 일 때, 최소 거리로 이동하면서 5개의 집에 배달 및 수거하는 과정을 나타낸 예시입니다.
배달 및 수거할 재활용 택배 상자 개수
| 집 #1 | 집 #2 | 집 #3 | 집 #4 | 집 #5 |
---|
배달 | 1개 | 0개 | 3개 | 1개 | 2개 |
수거 | 0개 | 3개 | 0개 | 4개 | 0개 |
배달 및 수거 과정
| 집 #1 | 집 #2 | 집 #3 | 집 #4 | 집 #5 | 설명 |
---|
남은 배달/수거 | 1/0 | 0/3 | 3/0 | 1/4 | 2/0 | 물류창고에서 택배 3개를 트럭에 실어 출발합니다. |
남은 배달/수거 | 1/0 | 0/3 | 3/0 | 0/4 | 0/0 | 물류창고에서 5번째 집까지 이동하면서(거리 5) 4번째 집에 택배 1개를 배달하고, 5번째 집에 택배 2개를 배달합니다. |
남은 배달/수거 | 1/0 | 0/3 | 3/0 | 0/0 | 0/0 | 5번째 집에서 물류창고까지 이동하면서(거리 5) 4번째 집에서 빈 택배 상자 4개를 수거한 후, 수거한 빈 택배 상자를 물류창고에 내리고 택배 4개를 트럭에 싣습니다. |
남은 배달/수거 | 0/0 | 0/3 | 0/0 | 0/0 | 0/0 | 물류창고에서 3번째 집까지 이동하면서(거리 3) 1번째 집에 택배 1개를 배달하고, 3번째 집에 택배 3개를 배달합니다. |
남은 배달/수거 | 0/0 | 0/0 | 0/0 | 0/0 | 0/0 | 3번째 집에서 물류창고까지 이동하면서(거리 3) 2번째 집에서 빈 택배 상자 3개를 수거한 후, 수거한 빈 택배 상자를 물류창고에 내립니다. |
16(=5+5+3+3)의 거리를 이동하면서 모든 배달 및 수거를 마쳤습니다. 같은 거리로 모든 배달 및 수거를 마치는 다른 방법이 있지만, 이보다 짧은 거리로 모든 배달 및 수거를 마치는 방법은 없습니다.
트럭에 실을 수 있는 재활용 택배 상자의 최대 개수를 나타내는 정수 cap
, 배달할 집의 개수를 나타내는 정수 n
, 각 집에 배달할 재활용 택배 상자의 개수를 담은 1차원 정수 배열 deliveries
와 각 집에서 수거할 빈 재활용 택배 상자의 개수를 담은 1차원 정수 배열 pickups
가 매개변수로 주어집니다. 이때, 트럭 하나로 모든 배달과 수거를 마치고 물류창고까지 돌아올 수 있는 최소 이동 거리를 return 하도록 solution 함수를 완성해 주세요.
제한사항
- 1 ≤ cap ≤ 50
- 1 ≤ n ≤ 100,000
- deliveries의 길이 = pickups의 길이 = n
- deliveries[i]는 i+1번째 집에 배달할 재활용 택배 상자의 개수를 나타냅니다.
- pickups[i]는 i+1번째 집에서 수거할 빈 재활용 택배 상자의 개수를 나타냅니다.
- 0 ≤ deliveries의 원소 ≤ 50
- 0 ≤ pickups의 원소 ≤ 50
- 트럭의 초기 위치는 물류창고입니다.
입출력 예
| cap | n | deliveries | pickups | result | | :— | :— | :— | :— | :— | | 4 | 5 | [1, 0, 3, 1, 2] | [0, 3, 0, 4, 0] | 16 | | 2 | 7 | [1, 0, 2, 0, 1, 0, 2] | [0, 2, 0, 1, 0, 2, 0] | 30 |
입출력 예 설명
입출력 예 #1
입출력 예 #2 배달 및 수거할 재활용 택배 상자 개수
| 집 #1 | 집 #2 | 집 #3 | 집 #4 | 집 #5 | 집 #6 | 집 #7 |
---|
배달 | 1개 | 0개 | 2개 | 0개 | 1개 | 0개 | 2개 |
수거 | 0개 | 2개 | 0개 | 1개 | 0개 | 2개 | 0개 |
배달 및 수거 과정
| 집 #1 | 집 #2 | 집 #3 | 집 #4 | 집 #5 | 집 #6 | 집 #7 | 설명 |
---|
남은 배달/수거 | 1/0 | 0/2 | 2/0 | 0/1 | 1/0 | 0/2 | 2/0 | 물류창고에서 택배 2개를 트럭에 실어 출발합니다. |
남은 배달/수거 | 1/0 | 0/2 | 2/0 | 0/1 | 1/0 | 0/2 | 0/0 | 물류창고에서 7번째 집까지 이동하면서(거리 7) 7번째 집에 택배 2개를 배달합니다. |
남은 배달/수거 | 1/0 | 0/2 | 2/0 | 0/1 | 1/0 | 0/0 | 0/0 | 7번째 집에서 물류창고까지 이동하면서(거리 7) 6번째 집에서 빈 택배 상자 2개를 수거한 후, 수거한 빈 택배 상자를 물류창고에 내리고 택배 2개를 트럭에 싣습니다. |
남은 배달/수거 | 1/0 | 0/2 | 1/0 | 0/1 | 0/0 | 0/0 | 0/0 | 물류창고에서 5번째 집까지 이동하면서(거리 5) 3번째 집에 택배 1개를 배달하고, 5번째 집에 택배 1개를 배달합니다. |
남은 배달/수거 | 1/0 | 0/1 | 1/0 | 0/0 | 0/0 | 0/0 | 0/0 | 5번째 집에서 물류창고까지 이동하면서(거리 5) 4번째 집에서 빈 택배 상자 1개를 수거하고 2번째 집에서 빈 택배 상자 1개를 수거한 후, 수거한 빈 택배 상자를 물류창고에 내리고 택배 2개를 트럭에 싣습니다. |
남은 배달/수거 | 0/0 | 0/1 | 0/0 | 0/0 | 0/0 | 0/0 | 0/0 | 물류창고에서 3번째 집까지 이동하면서(거리 3) 1번째 집에 택배 1개를 배달하고, 3번째 집에 택배 1개를 배달합니다. |
남은 배달/수거 | 0/0 | 0/0 | 0/0 | 0/0 | 0/0 | 0/0 | 0/0 | 3번째 집에서 물류창고까지 이동하면서(거리 3) 2번째 집에서 빈 택배 상자 1개를 수거한 후, 수거한 빈 택배 상자를 물류창고에 내립니다. |
30(=7+7+5+5+3+3)의 거리를 이동하면서 모든 배달 및 수거를 마쳤습니다. 같은 거리로 모든 배달 및 수거를 마치는 다른 방법이 있지만, 이보다 짧은 거리로 모든 배달 및 수거를 마치는 방법은 없습니다. 따라서, 30을 return 하면 됩니다.
풀이
Go
구현
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
| func solution(cap int, n int, deliveries []int, pickups []int) int64 {
var answer int64
d := []int{}
p := []int{}
for i:=n-1; i>=0; i-- {
if deliveries[i] != 0 {
d = append(d, i)
}
if pickups[i] != 0 {
p = append(p, i)
}
}
for len(d) != 0 || len(p) != 0 {
max := -1
if len(d) > 0 && d[0] > max {
max = d[0]
}
if len(p) > 0 && p[0] > max {
max = p[0]
}
answer += (int64(max) + 1) * 2
delivery, pickup := 0, 0
for len(d) > 0 {
now := d[0]
if delivery + deliveries[now] > cap {
deliveries[now] -= cap - delivery
break
} else {
delivery += deliveries[now]
deliveries[now] = 0
d = d[1:]
}
}
for len(p) > 0 {
now := p[0]
if pickup + pickups[now] > cap {
pickups[now] -= cap - pickup
break
} else {
pickup += pickups[now]
pickups[now] = 0
p = p[1:]
}
}
}
return answer
}
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
| 테스트 1 〉 통과 (0.00ms, 4.19MB)
테스트 2 〉 통과 (0.00ms, 4.23MB)
테스트 3 〉 통과 (0.00ms, 3.73MB)
테스트 4 〉 통과 (0.00ms, 3.56MB)
테스트 5 〉 통과 (0.01ms, 3.57MB)
테스트 6 〉 통과 (0.01ms, 4.23MB)
테스트 7 〉 통과 (0.05ms, 4.23MB)
테스트 8 〉 통과 (0.05ms, 3.56MB)
테스트 9 〉 통과 (0.19ms, 4.16MB)
테스트 10 〉 통과 (0.28ms, 4.21MB)
테스트 11 〉 통과 (0.16ms, 4.11MB)
테스트 12 〉 통과 (0.12ms, 3.55MB)
테스트 13 〉 통과 (0.14ms, 4.27MB)
테스트 14 〉 통과 (0.14ms, 4.22MB)
테스트 15 〉 통과 (4.48ms, 12.5MB)
테스트 16 〉 통과 (13.43ms, 14.2MB)
테스트 17 〉 통과 (5.63ms, 13.5MB)
테스트 18 〉 통과 (7.44ms, 15.9MB)
테스트 19 〉 통과 (4.56ms, 12.8MB)
테스트 20 〉 통과 (4.68ms, 13.9MB)
|
- 방문해야 하는 집들의 인덱스를 역순으로 Array에 넣는다.
- 배송, 픽업 Array에서 첫번째 값들을 꺼내 더 큰 값을 찾으면 해당 회차에서 방문해야 할 가장 먼 집의 위치이다.
- 배송, 픽업 각각의 거리에서 값을 누적해서
cap
이하를 만족할 때까지 나아간다.- 특정 거리까지의 합이
cap
보다 작을경우 해당 값을 Array에서 제거한다.
누적합
1
2
3
4
5
6
7
8
9
10
11
12
13
14
| func solution(cap int, n int, deliveries []int, pickups []int) int64 {
var answer int64
d, p := 0, 0
for i:=n-1; i>=0; i-- {
d -= deliveries[i]
p -= pickups[i]
for d < 0 || p < 0 {
answer += (int64(i) + 1) * 2
d += cap
p += cap
}
}
return answer
}
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
| 테스트 1 〉 통과 (0.00ms, 4.2MB)
테스트 2 〉 통과 (0.00ms, 3.54MB)
테스트 3 〉 통과 (0.00ms, 3.72MB)
테스트 4 〉 통과 (0.00ms, 4.2MB)
테스트 5 〉 통과 (0.00ms, 3.54MB)
테스트 6 〉 통과 (0.00ms, 4.23MB)
테스트 7 〉 통과 (0.00ms, 3.54MB)
테스트 8 〉 통과 (0.01ms, 4.2MB)
테스트 9 〉 통과 (0.03ms, 4.2MB)
테스트 10 〉 통과 (0.03ms, 4.3MB)
테스트 11 〉 통과 (0.02ms, 4.12MB)
테스트 12 〉 통과 (0.02ms, 3.54MB)
테스트 13 〉 통과 (0.01ms, 3.54MB)
테스트 14 〉 통과 (0.01ms, 3.54MB)
테스트 15 〉 통과 (0.21ms, 8.07MB)
테스트 16 〉 통과 (2.60ms, 8.07MB)
테스트 17 〉 통과 (0.78ms, 8.13MB)
테스트 18 〉 통과 (0.50ms, 7.98MB)
테스트 19 〉 통과 (0.38ms, 8.19MB)
테스트 20 〉 통과 (0.40ms, 7.95MB)
|
n-1
번째 인덱스부터 거꾸로 내려오며 상자 갯수를 더해준다.- 배송, 픽업 중 상자의 갯수가 0을 초과하면 거리를 계산해서 더해준다.
- 배송, 픽업 상자의 갯수에서
cap
만큼 빼준다.
Python
구현
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
| def solution(cap, n, deliveries, pickups):
answer = 0
d, p = [], []
for i in range(n-1, -1, -1):
if deliveries[i]:
d.append(i)
if pickups[i]:
p.append(i)
while d or p:
max_ = -1
if d and d[0] > max_:
max_ = d[0]
if p and p[0] > max_:
max_ = p[0]
answer += (max_ + 1) * 2
delivery, pickup = 0, 0
while d:
now = d[0]
if delivery + deliveries[now] > cap:
deliveries[now] -= cap - delivery
break
else:
delivery += deliveries[now]
deliveries[now] = 0
d.pop(0) # d = d[1:] 은 실패
while p:
now = p[0]
if pickup + pickups[now] > cap:
pickups[now] -= cap - pickup
break
else:
pickup += pickups[now]
pickups[now] = 0
p.pop(0)
return answer
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
| 테스트 1 〉 통과 (0.02ms, 10.1MB)
테스트 2 〉 통과 (0.01ms, 10.2MB)
테스트 3 〉 통과 (0.03ms, 10.2MB)
테스트 4 〉 통과 (0.02ms, 10.3MB)
테스트 5 〉 통과 (0.06ms, 10.3MB)
테스트 6 〉 통과 (0.05ms, 10.2MB)
테스트 7 〉 통과 (1.43ms, 10.2MB)
테스트 8 〉 통과 (2.74ms, 10.3MB)
테스트 9 〉 통과 (12.49ms, 10.4MB)
테스트 10 〉 통과 (10.31ms, 10.2MB)
테스트 11 〉 통과 (6.27ms, 10.2MB)
테스트 12 〉 통과 (4.22ms, 10.2MB)
테스트 13 〉 통과 (4.65ms, 10.4MB)
테스트 14 〉 통과 (4.93ms, 10.3MB)
테스트 15 〉 통과 (410.26ms, 15MB)
테스트 16 〉 통과 (3323.78ms, 16MB)
테스트 17 〉 통과 (1276.27ms, 16.1MB)
테스트 18 〉 통과 (2048.58ms, 16.1MB)
테스트 19 〉 통과 (768.14ms, 15.8MB)
테스트 20 〉 통과 (1362.71ms, 16MB)
|
- go로 풀었던 방법과 동일한 풀이 이지만 아슬아슬하게 통과됐다.
- 방문했던 곳을 제거하는 과정에서 슬라이싱을 하게되면 메모리 카피로인해 시간초과로 실패한다.
누적합
1
2
3
4
5
6
7
8
9
10
11
12
| def solution(cap, n, deliveries, pickups):
answer = 0
d, p = 0, 0
for i in range(n - 1, -1, -1):
d += deliveries[i]
p += pickups[i]
while d > 0 or p > 0:
d -= cap
p -= cap
answer += (i + 1) * 2
return answer
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
| 테스트 1 〉 통과 (0.01ms, 10.1MB)
테스트 2 〉 통과 (0.00ms, 10.2MB)
테스트 3 〉 통과 (0.01ms, 10.4MB)
테스트 4 〉 통과 (0.01ms, 10.2MB)
테스트 5 〉 통과 (0.01ms, 10.2MB)
테스트 6 〉 통과 (0.01ms, 10.2MB)
테스트 7 〉 통과 (0.19ms, 10.1MB)
테스트 8 〉 통과 (0.45ms, 10.2MB)
테스트 9 〉 통과 (2.19ms, 10.3MB)
테스트 10 〉 통과 (2.86ms, 10.4MB)
테스트 11 〉 통과 (0.88ms, 10.4MB)
테스트 12 〉 통과 (0.75ms, 10.3MB)
테스트 13 〉 통과 (1.16ms, 10.4MB)
테스트 14 〉 통과 (1.17ms, 10.3MB)
테스트 15 〉 통과 (16.30ms, 11.6MB)
테스트 16 〉 통과 (580.83ms, 11.7MB)
테스트 17 〉 통과 (50.10ms, 11.6MB)
테스트 18 〉 통과 (22.83ms, 11.5MB)
테스트 19 〉 통과 (20.45ms, 11.7MB)
테스트 20 〉 통과 (37.94ms, 11.4MB)
|