2 분 소요

1. 문제

https://www.acmicpc.net/problem/1939

  • BFS, 이진탐색 문제
// 문제
N(2 ≤ N ≤ 10,000)개의 섬으로 이루어진 나라가 있다.
이들 중 몇 개의 섬 사이에는 다리가 설치되어 있어서 차들이 다닐 수 있다.

영식 중공업에서는 두 개의 섬에 공장을 세워 두고
물품을 생산하는 일을 하고 있다.
물품을 생산하다 보면 공장에서 다른 공장으로
생산 중이던 물품을 수송해야 할 일이 생기곤 한다.
그런데 각각의 다리마다 중량제한이 있기 때문에
무턱대고 물품을 옮길 순 없다.
만약 중량제한을 초과하는 양의 물품이 다리를 지나게 되면 다리가 무너지게 된다.

한 번의 이동에서 옮길 수 있는 물품들의 중량의 최댓값을 구하는 프로그램을 작성하시오.

// 입력
첫째 줄에 N, M(1 ≤ M ≤ 100,000)이 주어진다.
다음 M개의 줄에는 다리에 대한 정보를 나타내는 세 정수
A, B(1 ≤ A, B ≤ N), C(1 ≤ C ≤ 1,000,000,000)가 주어진다.
이는 A번 섬과 B번 섬 사이에 중량제한이 C인 다리가 존재한다는 의미이다.
서로 같은 두 섬 사이에 여러 개의 다리가 있을 수도 있으며,
모든 다리는 양방향이다.
마지막 줄에는 공장이 위치해 있는 섬의 번호를 나타내는
서로 다른 두 정수가 주어진다.
공장이 있는 두 섬을 연결하는 경로는 항상 존재하는 데이터만 입력으로 주어진다.

// 출력
첫째 줄에 답을 출력한다.

// 예제 입력 1
3 3
1 2 2
3 1 3
2 3 2
1 3

// 예제 출력 1
3


2. 핵심 아이디어

  • 다리의 개수 M은 최대 100,000이며, 중량 제한 C는 최대 1,000,000,000
  • 이진 탐색을 이용하여 O(M * logC)에 문제를 해결할 수 있음
  • 한 번의 이동에서 옮길 수 있는 물품들의 중량의 최댓값을 이진 탐색으로 찾음


3. Python 문제풀이

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

def bfs(c) :
  queue = deque([start_node])
  visited = [False] * (n + 1)
  visited[start_node] = True
  while queue :
    x = queue.popleft()
    for y, weight in adj[x] :
      if not visited[y] and weight >= c :
        visited[y] = True
        queue.append(y)
  return visited[end_node]

start = 1000000000
end = 1

n, m = map(int, input().split())
adj = [[] for _ in range(n + 1)]

for _ in range(m) :
  x, y, weight = map(int, input().split())
  adj[x].append((y, weight))
  adj[y].append((x, weight))
  start = min(start, weight)
  end = max(end, weight)

start_node, end_node = map(int, input().split())

result = start
while (start <= end) :
  mid = (start + end) // 2
  if bfs(mid) :
    result = mid
    start = mid + 1
  else :
    end = mid - 1

print(result)


4. Java 문제풀이

import java.util.ArrayList;
import java.util.List;
import java.util.Scanner;

public class Main {
  static boolean check(List<Weight>[] a, int limit, int start, int end, boolean [] b) {
    if(b[start])
      return false;
    b[start] = true;
    if(start == end)
      return true;
    for(Weight v : a[start]) {
      if(v.g >= limit) {
        if(check(a, limit, v.v, end, b)){
          return true;
        }
      }
    }
    return false;
  }

  public static void main(String[] args) {
    Scanner sc = new Scanner(System.in);
    int n = sc.nextInt();
    int m = sc.nextInt();
    List<Weight> [] a = (List<Weight> []) new ArrayList[n+1];

    for(int i=1; i<=n; i++)
      a[i] = new ArrayList<>();

    int max = 0;
    for(int i=0; i<m; i++) {
      int v1 = sc.nextInt();
      int v2 = sc.nextInt();
      int g = sc.nextInt();
      a[v1].add(new Weight(v2, g));
      a[v2].add(new Weight(v1, g));
      max = Math.max(g, max);
    }

    int tx = sc.nextInt();
    int ty = sc.nextInt();
    int start = 1;
    int end = max;
    int ans = 0;

    while (start <= end) {
      boolean [] b = new boolean[n+1];
      int mid = (start + end) / 2;
      if (check(a, mid, tx, ty, b)) {
        start = mid + 1;
        ans = Math.max(ans, mid);
      }
      else
        end = mid - 1;
    }
    System.out.println(ans);
  }
}

class Weight{
  int v;
  int g;

  public Weight(int v, int g) {
    this.v = v;
    this.g = g;
  }
}

댓글남기기