[ 백준 ] 14921 / 용액 합성하기

金弘均·2021년 9월 16일
0

Baekjoon Online Judge

목록 보기
209/228
post-thumbnail

# Appreciation

/*
 * Problem :: 14921 / 용액 합성하기
 *
 * Kind :: Two Pointers
 *
 * Insight
 * - 그냥 for 문 두 번 돌리면 되겠지만
 *   그러면 O(N^2) 가 되어 시간초과다 <= N=10^5
 *
 * - 주어지는 용액의 순서를 바꾸어도
 *   문제를 푸는데 있어서 상관없다
 *   + 일단 정렬하고 보자 <= NlogN 이니 시간초과 걱정은 없다
 *   + 이제 다음과 같은 (값이 정렬된) 입력이 들어왔다고 하자
 *     -101 -3 -1 5 93
 *     # 어디서부터 찾아야 할까...?
 *       -> 일단 가운데서 탐색을 시작하기 까다롭다
 *          어떤 두 용액부터 섞으면서 탐색해야할지부터 모르겠다
 *       -> 처음의 두 용액부터 탐색해볼까?
 *          (-101, -3) 다음에 (-101, -1) 을 탐색해야할지 (-3, -1) 을 탐색해야할지 모르겠다
 *       -> 마지막 두 용액부터 탐색해볼까?
 *          마찬가지로 (93, 5) 다음에 (93, -1) 을 탐색해야할지 (5, -1) 을 탐색해야할지 모르겠다
 *       -> 처음과 끝 용액부터 탐색해볼까?
 *          (-101, 93) 을 섞으면 특성값이 8 이다
 *          여기서 (-3, 93) 을 탐색하는 것은 무의미하다
 *          <- 특성값이 양수이므로 절댓값이 커질 것이니까
 *          그렇다면 (-101, 5) 를 탐색해야 한다
 *          <- 혹시 특성값이 작아져서 절댓값이 작아질 수 있으니까
 *          이렇게 탐색을 진행하면 될 것 같다!
 *
 * Point
 * - 여기서 왼쪽 용액(값이 작은 용액)의 인덱스를 s
 *   오른쪽 용액(값이 큰 용액)의 인덱스를 e 라고 했을 때,
 *   [s, e] 까지의 범위가 답을 찾을 수 있는 탐색의 범위이다 <= 당연한 얘기지만
 *   + for (int i=s; i<=e; i++) {
 *         for (int j=s; j<=e; j++) {
 *             int sum = A[s] + A[e];
 *             if (sum > 0) break;
 *             ...
 *     # 여기서 어느 순간에 sum > 0 이 된다면 이후 sum 은 계속 증가할 것이기 때문에
 *       <- 값이 오름차순으로 정렬되어있으니까
 *       이후 j 를 다루는 for 문은 무의미한 연산이 된다
 *   + for (int i=e; i>=s; i--) {
 *         for (int j=e; j>=s; j--) {
 *             int sum = A[s] + A[e];
 *             if (sum < 0) break;
 *             ...
 *     # 여기서 어느 순간에 sum < 0 이 된다면 이후 sum 은 계속 감소할 것이기 때문에
 *       <- 값이 오름차순으로 정렬됨
 *       이후 j 를 다루는 for 문은 무의미한 연산이 된다
 *       -> 여기서 사용된 투 포인터 알고리즘은\
 *          위의 최적화를 동시에 적용할 수 있게 해주는 것으로 볼 수 있다!
 */

# Code

//
//  BOJ
//  ver.C++
//
//  Created by GGlifer
//
//  Open Source

#include <iostream>
#include <algorithm>

using namespace std;

#define endl '\n'

// Set up : Global Variables
#define INF 987654321

// Set up : Functions Declaration
/* None */


int main()
{
    // Set up : I/O
    ios::sync_with_stdio(false);
    cin.tie(nullptr);

    // Set up : Input
    int N; cin >> N;
    int A[N];
    for (int i=0; i<N; i++)
        cin >> A[i];

    // Process
    sort(A, A+N); /* 용액을 오름차순으로 정렬 */
    int s = 0, e = N-1; /* 섞을 용액에서 값이 작은 용액(왼쪽)과 값이 큰 용액(오른쪽) 인덱스 */
    int ans = INF; /* 두 개의 용액을 혼합하여 만들 수 있는 0 에 가장 가까운 특성값 */
    while (s < e) { /* 왼쪽 용액의 인덱스가 오른쪽 용액의 인덱스보다 작을 때 */
        int sum = A[s] + A[e]; /* 두 용액을 섞어 특성값을 구함 */
        ans = (abs(ans) > abs(sum)) ? sum : ans; /* ans 값 갱신 */
        if (ans == 0) break; /* ans 가 0 이면 더이상 탐색을 진행하는 것은 무의미함
                              * 0 과 가장 가까운 수는 0 */
        (sum > 0) ? e-- : s++; /* 특성값이 양수면 오른쪽 용액 인덱스를 감소시켜
                                * 특성값을 감소시킴
                                * 특성값이 음수면 왼쪽 용액 인덱스를 증가시켜
                                * 특성값을 증가시킴 */
    }

    // Control : Output
    cout << ans << endl;
}

// Helper Functions
/* None */
profile
이런 미친 게임을 봤나! - 옥냥이

0개의 댓글