(BOJ) 백준 1939 – 무게 제한 솔루션

1. 문제

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

1939: 무게 제한

N 및 M(1 ≤ M ≤ 100,000)은 첫 번째 줄에 지정됩니다. 다음 M 행에는 브리지에 대한 정보를 나타내는 세 개의 정수 A, B(1 ≤ A, B ≤ N) 및 C(1 ≤ C ≤ 1,000,000,000)가 제공됩니다. 이것은 A 섬과 B 섬 사이에 무게 제한이 없음을 의미합니다.

www.acmicpc.net



2. 솔루션 포인트

  • 두 부분으로 구성된 검색 + BFS로 해결
  • 주요 데이터 구조
    • 목록() inList : 인접 리스트
    • long min : 주어진 간선 중 최소값
    • long max : 주어진 edge의 최대값
    • boolean() Visited : 방문 체크 배열
  • 각 다리에 무게가 할당되고 그 무게를 초과하지 않고 공장에서 공장으로 이동할 수 있는 최대 무게를 찾습니다.
  • 이 문제는 이진 검색에 관한 것입니다. 트렁크 비용오전.
  • 핵심은 이진 검색으로 Edge의 가중치를 결정한 후 BFS를 실행할 때 시작 노드(이 문제의 첫 번째 공장)에서 끝 노드(두 번째 공장)로 이동할 수 있는 최대 가중치를 찾는 것입니다.

3. 논리 풀기

  • 입력이 주어지면 양방향 인접 목록을 생성합니다.
  • 들어갈 때 부족 최소값 최대값컴퓨터에 저장
    • 이것은 두 부분으로 구성된 검색에서 나중에 수행됩니다. 왼쪽, 오른쪽으로 사용가치
  • 두 부분으로 구성된 검색 기능 weightRestrictionBinarySearch()달리다
    • 가장자리의 최대값과 최소값 왼쪽, 오른쪽으로 두 부분으로 구성된 검색의 양쪽 끝에서 값을 설정하도록 설정합니다.
    • 왼쪽 <= 오른쪽으로 평균은 (왼쪽 + 오른쪽) / 2에서 .
    • 이거는 WeightConstraintBFS()BFS를 실행합니다.
      1. BFS 기능을 수행할 때 queue에서 가져온 객체가 터미널 노드라면 i. 시간. 두 번째 공장 진실두 번째 공장으로 이동할 수 없는 경우 반환 잘못된보고
      2. 이 시점에서 다음 노드를 찾을 때 주의해야 합니다. 센터가다 다음 노드 에지의 가중치가 작거나 같으면 검색할 수 있습니다.”
      3. 다리를 건너려면 그 가장자리의 무게보다 작거나 같아야 하기 때문입니다.
    • 만약에 WeightConstraintBFS()반환된 값 진실이것은 평균 집합으로 목표가 달성되었음을 의미하므로 결과를 업데이트하고 왼쪽 값을 평균 + 1로 설정합니다.
    • 만약에 반환된 값 잘못된, 목표가 충족되지 않았으므로 값을 줄여야 함을 의미합니다. 따라서 오른쪽에 중앙 – 1의 값을 할당합니다.


4. 소스 코드

import java.io.*;
import java.util.ArrayDeque;
import java.util.ArrayList;
import java.util.List;
import java.util.Queue;
import java.util.StringTokenizer;

public class Main {
	static int N; // 섬의 개수
	static int M; // 다리의 개수
	
	static class Node {
		int v;
		long cost;
		
		public Node(int v, long cost) {
			this.v = v;
			this.cost = cost;
		}
	}
	
	static List<Node>() inList; // 인접 리스트
	static long result = Integer.MIN_VALUE;
	
	static int start, end;
	static long min = Integer.MAX_VALUE; // 주어진 간선 중 최솟값
	static long max = Integer.MIN_VALUE; // 주어진 간선 중 최대 값
	
	static boolean() visited;
	
    public static void main(String() args) throws IOException {
        BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
        BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(System.out));
        
        // 입력을 받아 변수 초기화 및 인접리스트 초기화
        StringTokenizer st = new StringTokenizer(br.readLine());
        N = Integer.parseInt(st.nextToken());
        M = Integer.parseInt(st.nextToken());
        
        inList = new ArrayList(N + 1);
        for (int i = 1; i <= N; i++) {
        	inList(i) = new ArrayList<>();
        }
        
        for (int i = 0; i < M; i++) {
        	st = new StringTokenizer(br.readLine());
        	int from = Integer.parseInt(st.nextToken());
        	int to = Integer.parseInt(st.nextToken());
        	int cost = Integer.parseInt(st.nextToken());
        	
        	inList(from).add(new Node(to, cost));
        	inList(to).add(new Node(from, cost));
        	
        	// 간선의 최대값 구하기
        	min = Long.min(min, cost);
        	max = Long.max(max, cost);
        }
        
        // 출발 노드 번호 및 도착 노드 번호
        st = new StringTokenizer(br.readLine());
        start = Integer.parseInt(st.nextToken());
        end = Integer.parseInt(st.nextToken());
        
        // 이분탐색 함수 시작
        weightRestrictionBinarySearch();
        
        //결과 출력
        bw.write(Long.toString(result));
        bw.flush();
        bw.close();
        br.close();
    }

    // 이분 탐색 함수 : 이분탐색의 주체는 간선의 비용
	private static void weightRestrictionBinarySearch() {
		long left = min;
		long right = max;
		
		// weightRestrictionBFS의 리턴 값은 true or false
		// 만약 true가 리턴 됬다는 것은 도착지점에 도착했다는 것이므로 result를 갱신
		while (left <= right) {
			long mid = (left + right) / 2;
			
			if (weightRestrictionBFS(mid)) {
				result = Long.max(result, mid);
				
				left = mid + 1;
			} else {
				right = mid - 1;
			}
		}
	}
	
	// bfs 함수
	private static boolean weightRestrictionBFS(long mid) {
		// 방문 배열
		visited = new boolean(N + 1);
		
		// BFS를 위한 큐
		Queue<Node> q = new ArrayDeque<>();
		q.add(new Node(start, mid));
		visited(start) = true;
		
		while (!q.isEmpty()) {
			Node poll = q.poll();
			
			// 두번째 공장에 도착했다면
			if (poll.v == end) {
				return true;
			}
			
			for (int i = 0; i < inList(poll.v).size(); i++) {
				// 연결된 노드가 null이 아니고, 방문 처리하지 않았고, 
				// 지금 탐색하는 cost가 다음 노드 간선의 cost보다 작거나 같을 때 탐색할 수 있음
				if (inList(poll.v).get(i) != null && !visited(inList(poll.v).get(i).v)
						&& mid <= inList(poll.v).get(i).cost) {
					visited(inList(poll.v).get(i).v) = true;
					q.add(new Node(inList(poll.v).get(i).v, mid));
				}
			}
		}
		return false;
	}
}


5. 결과

65/100