[백준 JAVA] 8980 : 택배
2024. 7. 20. 20:26ㆍ백준
[백준 8980] 택배 : https://www.acmicpc.net/problem/8980
문제 조건 정리
- 트럭은 본부에서 출발하여 1번 마을부터 마지막 마을까지 오른쪽으로 가면서 마을에 있는 물건을 배송한다.
- 각 마을은 배송할 물건들을 박스에 넣어 보내며, 본부에서는 박스를 보내는 마을번호, 박스를 받는 마을번호와 보낼 박스의 개수를 알고 있다.
- 박스들은 모두 크기가 같다.
- 트럭에 최대로 실을 수 있는 박스의 개수, 즉 트럭의 용량이 있다.
- 이 트럭 한 대를 이용하여 다음의 조건을 모두 만족하면서 최대한 많은 박스들을 배송하려고 한다.
- 조건 1: 박스를 트럭에 실으면, 이 박스는 받는 마을에서만 내린다.
- 조건 2: 트럭은 지나온 마을로 되돌아가지 않는다.
- 조건 3: 박스들 중 일부만 배송할 수도 있다.
입력
- 박스를 받는 마을번호는 보내는 마을번호보다 크다.
이외 별로 중요하지 않다고 생각함.
문제를 풀기 전
- 부분 배낭과 비슷한 느낌으로 푸는 건가? -> 택배에 가치가 없음. 한계만 정해져 있으므로 다른 방법이 있을 듯
- 예시를 생각하다보니 택배 정보를 출발 마을이나 도착 마을을 기준으로 정렬하면 될 것 같다고 생각함
- 택배 정보를 출발 마을을 기준으로 정렬한다면,
첫 택배 정보가 최악의 경우 첫 마을에서 마지막 마을까지 트럭의 최대 용량을 담을 수 있음. - 택배 정보를 도착 마을을 기준으로 정렬한다면,
최악의 경우에도 다음 도착 마을로 향하는 택배 정보에 영향을 미치지 않음 -> 그리디
(최악의 경우, 예시)
도착 마을을 기준으로 정렬된 첫 택배 정보가 1번 마을 ~ n번 마을로 향할 때, 트럭의 최대 용량을 담아도
n+1번째 마을부터 출발하는 택배에게 영향을 미치지 않음 - 이외에, 부분적으로 택배를 담을 수 있는 것을 체크하는 로직을 추가하면 될 듯
코드
package baekJoon;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.StringTokenizer;
public class BJ8980 {
static private class Delivery {
int start, end, count;
public Delivery(int start, int end, int count) {
this.start = start;
this.end = end;
this.count = count;
}
}
public static void main(String[] args) throws IOException {
BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(System.in));
StringTokenizer stringTokenizer = new StringTokenizer(bufferedReader.readLine(), " ");
int townCount = Integer.parseInt(stringTokenizer.nextToken());
int capacity = Integer.parseInt(stringTokenizer.nextToken());
List<Delivery> deliveries = new ArrayList<>();
int n = Integer.parseInt(bufferedReader.readLine());
for (int i = 0; i < n; i++) {
stringTokenizer = new StringTokenizer(bufferedReader.readLine(), " ");
int start = Integer.parseInt(stringTokenizer.nextToken());
int end = Integer.parseInt(stringTokenizer.nextToken());
int count = Integer.parseInt(stringTokenizer.nextToken());
deliveries.add(new Delivery(start, end, count));
}
// 도착 마을을 기준으로 정렬
// 도착마을이 같다면 시작 마을을 기준으로 정렬
deliveries.sort((a, b) -> {
if (a.end == b.end) return a.start - b.start;
return a.end - b.end;
});
int[] truckCapacity = new int[townCount + 1]; // 마지막 도시는 필요없음
Arrays.fill(truckCapacity, capacity);
int answer = 0;
for (int i = 0; i < n; i++) {
// 현재 택배 정보
Delivery curr = deliveries.get(i);
// 현재 트럭이 해당 마을로 갔을 때, 해당 마을에서 담을 수 있는 택배의 개수 중 *최소값*
// 즉, 현재 트럭이 해당 경로에서 담을 수 있는 최대 택배 개수
int minCapacity = Integer.MAX_VALUE;
// 도착 마을은 택배를 내리므로 확인하지 않음
for (int s = curr.start; s < curr.end; s++) {
minCapacity = Math.min(minCapacity, truckCapacity[s]);
}
// 트럭이 실을 수 있는 택배의 양이 현재 택배 수보다 적다면
if (minCapacity < curr.count) {
answer += minCapacity; // 실을 수 있는 만큼만 싣는다
// 현재 택배 경로 동안
for (int s = curr.start; s < curr.end; s++) {
truckCapacity[s] -= minCapacity; // 실은 개수만큼 실을 수 없음
}
}
// 트럭이 모든 택배를 실을 수 있다면
else {
answer += curr.count; // 모두 싣는다
// 현재 택배 경로 동안
for (int s = curr.start; s < curr.end; s++) {
truckCapacity[s] -= curr.count; // 실은 개수만큼 실을 수 없음
}
}
}
System.out.println(answer);
}
}
문제를 풀고 난 후
1. 트럭이 해당 마을, 즉 경로이자 시점에서 택배를 얼마나 실었는지, 더 실을 수 있는지를 확인해야 한다는 것
2. 도착 마을을 기준으로 택배 정보를 정렬한다면 이후의 선택에 영향을 미치지 않는다는 것
위 요소들이 문제에서 어렵거나 헷갈릴 수 있는 점이라고 생각한다. 나는 1번은 헷갈렸고 2번은 어려웠다. 재밌다.
'백준' 카테고리의 다른 글
[백준 JAVA] 14466 : 소가 길을 건너간 이유 6 (0) | 2024.07.28 |
---|---|
[이분탐색] Upper / Lower Bound (1) | 2024.07.24 |
[백준 JAVA] 15989 : 1, 2, 3 더하기 4 (0) | 2024.07.16 |
[백준 JAVA] 17779 : 게리멘더링 2 (1) | 2024.07.11 |
[백준 JAVA] 15684 : 사다리 조작 (0) | 2024.07.10 |