길민호(ethan.mino)
코딩수첩
길민호(ethan.mino)
전체 방문자
오늘
어제
  • 분류 전체보기 (215)
    • Computer Science (0)
    • Web (6)
      • CSS (0)
      • HTML (0)
    • Node.js (0)
    • Javascript (2)
    • Java (46)
      • Spring (27)
      • Jsp (0)
    • C\C++ (2)
    • Programming (0)
    • AI (0)
    • Database (7)
    • Git (5)
    • Algorithm (119)
      • Stack (0)
      • Queue (0)
      • Linked List (0)
      • Sort (0)
      • Simulation (27)
      • Recursion (0)
      • Backtracking (4)
      • Two Pointer (3)
      • Dynamic Programming (19)
      • Greedy (10)
      • Graph (3)
      • Dijkstra (1)
      • BFS\DFS (8)
      • Floyd (1)
      • MST (4)
      • Tree (4)
      • Binary Search (8)
      • Binary Search Tree (4)
    • IntelliJ (4)
    • Vscode (0)
    • Operating System (0)
    • 후기 (3)
    • 성장일지 (13)
    • 스터디 (7)
    • 설치 (1)

블로그 메뉴

  • 홈
  • 태그
  • 방명록

공지사항

인기 글

태그

  • ㅡ

최근 댓글

최근 글

티스토리

hELLO · Designed By 정상우.
길민호(ethan.mino)

코딩수첩

[백준 2467번] 용액 (C++)
Algorithm/Binary Search

[백준 2467번] 용액 (C++)

2022. 5. 13. 05:54

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

 

2467번: 용액

첫째 줄에는 전체 용액의 수 N이 입력된다. N은 2 이상 100,000 이하의 정수이다. 둘째 줄에는 용액의 특성값을 나타내는 N개의 정수가 빈칸을 사이에 두고 오름차순으로 입력되며, 이 수들은 모두 -

www.acmicpc.net


용액문제는 이분탐색을 이용하여 해결할 수 있습니다. 

문제에서 N이 최대 100,000이므로, O(N2)의 알고리즘을 사용하는 경우, 시간초과가 발생할 수 있습니다. 

 

문제에서 용액의 특성값이 주어지고, 두 용액을 혼합했을 때, 0에 가장 가까운 용액을 만들어내는 두 용액을 찾아야 합니다.

 

첫번째 용액의 특성값이 10,000일 때의 그래프는 아래와 같습니다.

(X축은 두번째 용액의 특성값, Y축은 두 용액을 혼합했을 때, 0과의 거리)

따라서 특성값이 10,000에 가장 가까운 두번째 용액을 선택했을 때, 0에 가장 가까운 용액을 만들어낼 수 있습니다. 

즉, 첫번째 용액의 특성값이 S1일때, 특성값이 S1 * -1에 가장 가까운 용액 선택하면됩니다. 

이 두번째 용액을 탐색하는데 이분탐색이 사용됩니다. 

 

S1 * -1가 배열 내에 있으면 더이상 찾을 필요가 없지만,

S1 * -1이 배열 내에 없을 경우, s1 * -1을 배열에 넣었을 때, 정렬이 유지되는 가장 작은 idx를 찾으면 됩니다. 

 

예를 들어 S = {-99, -2, -1, 4, 98, 100}인 경우 혼합했을 때, 0에 가장 가까운 용액을 찾는 과정은 아래와 같습니다.

S1 = 99일때,

  1. 99를 배열 내에서 이분탐색으로 찾는다.
  2. 99가 배열 내에 존재하지 않기 때문에, 99를 배열 내에 삽입했을 때, 정렬이 유지되는 가장 작은 인덱스를 찾는다. 
  3. 가장 작은 인덱스는 5이다. (단, 인덱스는 0부터 시작)
  4. 인덱스가 N보다 작으므로, N번째 용액과, N -1번째 용액 중 S1과 혼합했을 때 0에 더 가까운 용액을 선택한다.

위와 같은 과정을 모든 용액에 대해 수행한 다음, 0에 더 가까운 용액을 만들 수 있는 두 용액을 찾으면 됩니다. 

 

전체 코드는 아래와 같습니다.

#include <bits/stdc++.h>
using namespace std;

int s[100010];
int main(){
    ios::sync_with_stdio(0);
    cin.tie(0);
    int n; cin >> n;    
    for(int i = 0; i < n; i++) cin >> s[i]; // 용액 입력 받음

    int m = INT_MAX;    // 0에 가장 가까운 특성값
    pair<int, int> selected;    // 혼합했을 때, 0에 가장 가까운 용액
    for(int i = 0; i < n; i++){ // 모든 용액에 대해, 혼합했을 때 0에 가장 가까운 두 번째 용액을 찾음
        int s2 = s[i] * -1; // s[i]와 섞었을 때 0이 되는 특성값
        
        bool exist = binary_search(s + (i + 1), s + n, s2); // s2를 배열 내에서 찾음
        if(exist){  // 찾은 경우
            selected = {min(s[i], s2), max(s[i], s2)};  
            break;  // 더이상 찾을 필요 없음
        }else{
            int idx = lower_bound(s + (i + 1), s + n, s2) - s;  // S2를 배열에 넣었을 때, 정렬이 유지되는 가장 작은 idx를 찾음
            
            // 단, 첫번째 용액과 두번째 용액이 같으면 안됨
            if(i != idx - 1 &&  m > abs(s[i] + s[idx - 1])){    // m보다 s[i] + s[idx - 1]가 0에 가깝다면
                selected = {min(s[i], s[idx - 1]), max(s[i], s[idx - 1])};
                m = abs(s[i] + s[idx - 1]);
            }

            if(idx < n){
                if(i != idx && m > abs(s[i] + s[idx])){ // m보다 s[i] + s[idx]가 0에 가깝다면
                    //cout << "3\n";
                    selected = {min(s[i], s[idx]), max(s[i], s[idx])};
                    m = abs(s[i] + s[idx]);
                }
            }
        }
    }

    cout << selected.first << " " << selected.second << "\n";
}

'Algorithm > Binary Search' 카테고리의 다른 글

[백준 2230번] 수 고르기  (0) 2022.05.16
[백준 3151번] 합이 0 (C++)  (0) 2022.05.13
[백준 18869] 멀티버스 2 (C++)  (3) 2022.05.13
[백준 16401번] 과자 나눠주기 (C++)  (0) 2022.05.12
[백준 2295번] 세 수의 합 (C++)  (0) 2022.05.12
    'Algorithm/Binary Search' 카테고리의 다른 글
    • [백준 2230번] 수 고르기
    • [백준 3151번] 합이 0 (C++)
    • [백준 18869] 멀티버스 2 (C++)
    • [백준 16401번] 과자 나눠주기 (C++)
    길민호(ethan.mino)
    길민호(ethan.mino)
    💻 호기심 많은 서버 개발자 길민호입니다.

    티스토리툴바