“[JAVA] 백준 1939번 중량제한 자바 풀이”
사용 알고리즘 : 이분 탐색, BFS, 매개 변수 탐색(Parametric Search)
📚 문제
🔗 문제 링크
📖 문제 설명
- N개의 섬으로 이루어진 나라가 있음
- 몇 개의 섬 사이에는 다리가 설치되어 있어서 물품을 운반할 수 있음
- 각 다리마다 중량제한이 있음
- 한 번의 이동에서 옮길 수 있는 물품들의 중량의 최댓값을 구해야 함
🔍 입력 조건
- 첫째 줄에 N(2 ≤ N ≤ 10,000), M(1 ≤ M ≤ 100,000)이 주어짐
- 다음 M개의 줄에는 다리에 대한 정보를 나타내는 세 정수 A, B(1 ≤ A, B ≤ N), C(1 ≤ C ≤ 1,000,000,000)가 주어짐
- 마지막 줄에는 공장이 위치해 있는 섬의 번호를 나타내는 서로 다른 두 정수가 주어짐
🔍 출력 조건
- 한 번의 이동에서 옮길 수 있는 물품들의 중량의 최댓값을 출력
🧩 문제 분류
- 알고리즘: 이분 탐색, BFS, 매개 변수 탐색(Parametric Search)
- 자료구조: 그래프(인접 리스트), 큐
- 난이도: Gold III
🚀 접근 방법
- 그래프를 인접 리스트로 구현하여 섬들의 연결 관계와 중량제한을 저장
- 이분 탐색으로 가능한 중량의 범위를 탐색 (1 ~ 최대 중량제한)
- BFS를 사용하여 해당 중량으로 시작점에서 도착점까지 이동 가능한지 확인
- 이동 가능하면 중량을 늘리고, 불가능하면 중량을 줄임
💻 구현
/**
* BAEKJOON ONLINE JUDGE
* 문제 이름 : 중량제한
* 문제 번호 : 1939
* 난이도 : GOLD III
*/
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.*;
public class BOJ1939 {
private static final int MAX_WEIGHT = 1000000000;
private static final int MAX_N = 10000;
static int N, M;
static List<List<Node>> graph; // 각 섬들마다 연결된 섬들
static int first, second; // 연결된 공장 1, 2
static boolean[] visited;
// 이동할 섬과 그 사이 거리를 Node Class로 설정
static class Node{
int v;
int weight;
public Node(int v, int weight) {
this.v = v;
this.weight = weight;
}
}
// BFS에서 무게를 인자로 받아 공장 간 이동이 가능한지 여부 판단
public static boolean bfs(int weight){
Queue<Integer> q = new LinkedList<>();
visited = new boolean[MAX_N + 1];
q.offer(first);
visited[first] = true;
while (!q.isEmpty()){
int curr = q.poll();
if (curr == second) return true;
for (Node n : graph.get(curr)){
// 이미 방문했거나 수용가능 무게가 현재 들고있는 무게보다 작다면 패스
if (visited[n.v] || n.weight < weight) continue;
q.offer(n.v);
visited[n.v] = true;
}
}
return false;
}
// 이분 탐색 구현 함수
// "무게"를 기준으로 이분탐색을 진행
public static int simulate(int s, int e){
int answer = 0;
while (s <= e){
int mid = (s + e) / 2;
// 이동 성공했다면 일단 현재의 최고 무게.
// 더 큰무게로 이동하여 계속 탐색 진행
if (bfs(mid)){
answer = mid;
s = mid + 1;
}
// 이동에 실패했다면 무게를 줄여서 다시 시작
else e = mid - 1;
}
return answer;
}
// Main
public static void main(String[] args) throws IOException {
BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
StringTokenizer st = new StringTokenizer(br.readLine());
N = Integer.parseInt(st.nextToken());
M = Integer.parseInt(st.nextToken());
// 그래프 초기화
graph = new ArrayList<>();
for (int i = 0; i <= N; i++){
graph.add(new ArrayList<>());
}
// 연결 리스트로 섬 간 연결
for (int i = 0; i < M; i++){
st = new StringTokenizer(br.readLine());
int A = Integer.parseInt(st.nextToken());
int B = Integer.parseInt(st.nextToken());
int C = Integer.parseInt(st.nextToken());
graph.get(A).add(new Node(B, C));
graph.get(B).add(new Node(A, C));
}
// 공장이 위치한 섬 두 가지.
st = new StringTokenizer(br.readLine());
first = Integer.parseInt(st.nextToken());
second = Integer.parseInt(st.nextToken());
System.out.println(simulate(1, MAX_WEIGHT));
}
}
⏱ 시간 복잡도
- O(M log C * (N + M)), 여기서 C는 최대 중량제한
- 이분 탐색: O(log C)
- 각 단계에서 BFS: O(N + M)
💾 공간 복잡도
- O(N + M): 그래프를 저장하는 인접 리스트의 크기
🧪 테스트 케이스
입력 | 출력 |
---|---|
3 3 1 2 2 3 1 3 2 3 2 1 3 | 3 |
📝 회고
- 그래프 문제와 이분 탐색이 결합된 형태라 재미있었음.
- 전혀 못풀던 이분탐색 문제를 어느정도는 알게 된 느낌?
- 최대값이 1,000,000,000이면 int 범위 내에서 풀이 가능
- 최대값이 2^32-1 이런 식이면 Long으로 풀어야 함.