본문 바로가기
백준(C++)/이분 탐색

[BOJ/C++]2110번_공유기 설치(★)

by 코잼민 2024. 7. 23.

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

 

##문제 이해하기

 

##코드 작성 전 알아야 할 개념 && 코드 논리 :

1_ 첫번째 집을 공유기를 설치했다고, 가정 => 그 다음 순차탐색으로 집을 순회하면서, 다음 공유기를 설치할 집을 찾는 IDEA

if (mid <= 순회하면서, 공유기 설치한 집과의 인접 거리) : 공유기 설치개수++ , 인접 공유기 변수 업데이트

(자세한 설명은 밑의 노트)

2_ (1_)과정의 집을 순회하면서, 공유기 설치 후 => 설치된 공유기 개수 vs 입력한 공유기를 설치해야할 개수(C) 비교

=> 이분탐색

3_★Upper_Bound 이분탐색 vs Basic 이분탐색 :

어떤 값을 찾는 것이 아닌, 건에 맞지만, 그 중 최대거리를 찾는 과정이기 때문에, Upper_Bound로 코드 구현해야한다.

※참고 설명 :

일반적인 이분 탐색 (Binary Search)

일반적인 이분 탐색은 주로 정렬된 배열에서 특정 값을 찾을 때 사용됩니다. 이 경우에는 특정 값이 배열에 존재하는지를 확인하는 것이 목표입니다.

  • 사용 상황: 배열이나 리스트에서 특정 값의 존재 여부를 확인하거나, 특정 값을 찾는 경우.
  • 예시 문제: 정렬된 배열에서 숫자 7이 있는지 확인하는 문제.

상한/하한 경계를 찾는 이분 탐색 (Upper Bound/Lower Bound)

상한 경계(Upper Bound)나 하한 경계(Lower Bound)를 찾는 이분 탐색은 주로 값의 범위를 다루는 문제에서 사용됩니다. 여기서 Upper Bound는 특정 값보다 큰 첫 번째 위치를, Lower Bound는 특정 값보다 크거나 같은 첫 번째 위치를 의미합니다. 이 경우, 값 자체를 찾는 것이 아니라 값이 위치할 수 있는 범위를 찾는 것이 목표입니다.

  • 사용 상황: 배열이나 리스트에서 특정 값보다 크거나 작은 값이 처음으로 나타나는 위치를 찾거나, 특정 조건을 만족하는 최대 또는 최소 값을 찾는 경우.
  • 예시 문제: 정렬된 배열에서 특정 값보다 크거나 같은 첫 번째 위치를 찾는 문제, 또는 두 요소 사이의 최대/최소 간격을 찾는 문제.

Upper Bound를 사용한 이분 탐색 예시

주어진 문제(공유기 설치 문제)는 Upper Bound를 사용하여 해결할 수 있는 전형적인 예입니다. 여기서는 두 공유기 사이의 최대 거리를 찾기 위해 Upper Bound를 사용하여 가능한 최대 간격을 탐색합니다. 이는 특정 간격(mid)을 기준으로 공유기를 설치할 수 있는지 여부를 확인하며, 가능한 최대 간격을 탐색하는 과정입니다.

문제 예시

  • 문제: N개의 집에 C개의 공유기를 설치할 때, 가장 인접한 두 공유기 사이의 거리를 최대로 하려면 그 최대 거리는 얼마인가?
  • Upper Bound 사용 이유: 특정 간격(mid)을 기준으로 공유기를 설치할 수 있는지 확인하고, 가능한 최대 거리를 탐색하는 것이 목표입니다.

Lower Bound를 사용한 이분 탐색 예시

Lower Bound는 주어진 값 이상이 처음 나타나는 위치를 찾는 데 사용됩니다. 이는 특정 값보다 작지 않은 첫 위치를 찾는 데 유용합니다.

##코드 논리 분석 노트 :

##코드 :

 

 

 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
#include <iostream>
#include <vector>
#include <algorithm>
 
using namespace std;
 
void init() {
    ios::sync_with_stdio(false);
    cin.tie(0);
    cout.tie(0);
}
 
int main() {
    init();
    int N, C;
    cin >> N >> C;
 
    vector<unsigned int> V(N);
    for (int i = 0; i < N; i++) {
        cin >> V[i];
    }
 
    // 오름차순 정렬
    sort(V.begin(), V.end());
 
    unsigned int start = 1;//두 인접한 공유기의 최소 거리(모든 경우의 수 중)
    unsigned int end = V[N - 1- V[0];//입력된 공유기들 중 가장 먼 거리
    unsigned int ans = 0;
 
    // 이분 탐색
    while (start <= end) {
        unsigned int mid = (start + end/ 2;
 
        //맨 첫번째 집을 공유기 설치했다고, 가정
        int cnt = 1;//설치된 공유기 개수
        unsigned int last_h = V[0];//공유기가 설치된 첫번째 집의 위치
 
        for (int i = 1; i < N; i++)//2번째 집부터 스캔 
        {
 
            if (V[i] - last_h >= mid) //이분 탐색된 거리 vs 공유기의 사이 거리 비교
            {
                //공유기 거리 >=거리
                cnt++;//공유기 설치
                last_h = V[i];//인접 공유기 업데이트
            }
 
        }
 
        //Upper Bound
        if (cnt>=C) 
        {
            ans = mid;
            start = mid + 1;
        }
        else {
            end = mid - 1;
        }
    }
 
    cout << ans << '\n';
 
    return 0;
}
 
cs

'백준(C++) > 이분 탐색' 카테고리의 다른 글

[BOJ/C++]2805번_나무자르기  (3) 2024.07.22