[백준] 중량제한
이진탐색
그래프
백준
medium
문제
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인 다리가 존재한다는 의미이다. 서로 같은 두 도시 사이에 여러 개의 다리가 있을 수도 있으며, 모든 다리는 양방향이다. 마지막 줄에는 공장이 위치해 있는 섬의 번호를 나타내는 서로 다른 두 정수가 주어진다. 공장이 있는 두 섬을 연결하는 경로는 항상 존재하는 데이터만 입력으로 주어진다.
3 3
1 2 2
3 1 3
2 3 2
1 3
출력
첫째 줄에 답을 출력한다.
3
이진탐색으로 최대 중량을 구한다.
- C의 크기가 10억이므로 이를 O(logn)으로 만들어야한다는 힌트를 얻을 수 있다.
- c의 크기를 이진 탐색하면서, 해당 중량으로 공장이 있는 섬을 방문할 수 있는지 확인한다.
while start <= end:
mid = (start + end) // 2
# 이 가중치로 공장을 방문할 수 있는지 확인
if bfs(mid):
result = mid
start = mid + 1
else:
end = mid - 1
BFS로 공장이 있는 섬을 방문하는지 확인한다.
- 입력받은 간선을
vice-versa
의 쌍으로 구성을 한다. - 그래야만 연결된 모든 간선을 반복적으로
visit
할 수 있다.
BFS
1. 인접한 노드를 [Key-Value] vice-versa 쌍으로 가지고 있다.
2. 방문해야할 노드를 저장할 queue와, 방문을 했다는것을 표현할 list를 준비한다.
3. need_visit 큐에서 선입선출로 노드를 빼와서 순회한다.
4. need_visit 큐에 원소가 없어질때 까지 반복한다.
-
dict() 구조가 아니라, 배열의 인덱스를 노드로 활용한다.
adj = [[] for _ in range(n+1)] # 첫번째 노드를 인덱스로 사용할 것이기 때문에 n+1 for _ in range(m): x, y, weight = map(int, input().split(' ')) # 모든 연결된 간선을 탐색하기 위해서 # vice-versa로 간선 추가 adj[x].append((y, weight)) adj[y].append((x, weight))
-
파이썬의 deque를 활용해서 queue를 만든다.
- start_node부터 시작한다.
- BFS는 너비우선탐색 (형제 노드들을 먼저 탐색)이므로 큐로 구현
def bfs(c): # 첫번째 노드부터 시작한다. queue = deque([start_node]) visited = [False] * (n + 1) visited[start_node] = True while queue: x = queue.popleft() # BFS는 큐로 구현하므로, 선입선출로 구현 for y, weight in adj[x]: if not visited[y] and weight >= c: visited[y] = True queue.append(y) return visited[end_node]