본문 바로가기
백준BOJ/정렬, 투 포인터

백준 2470 두 용액

by 이일아 2022. 7. 4.
반응형

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

 

2470번: 두 용액

첫째 줄에는 전체 용액의 수 N이 입력된다. N은 2 이상 100,000 이하이다. 둘째 줄에는 용액의 특성값을 나타내는 N개의 정수가 빈칸을 사이에 두고 주어진다. 이 수들은 모두 -1,000,000,000 이상 1,000,00

www.acmicpc.net

 

 

 

EXPLANATION

 

그런데 수열의 모든 수가 양수면 arr[0] + arr[1]의 절댓값이 가장 작고,

수열의 모든 수가 음수면 arr[N - 2] + arr[N - 1]의 절댓값이 가장 작다.

 

수열의 양음수가 섞여 있을 때,

입력되는 수들을 정렬시키고 양쪽끝에 두 포인터를 둔다.

두 수의 합이 0보다 작으면 왼쪽의 index를 한 칸 올려 음수의 크기를 줄이고,

두 수의 합이 0보다 크면 오른쪽의 index를 한 칸 내려 양수의 크기를 줄인다.

이를 두 포인터가 교차할 때 까지 반복하면서 두 포인터가 가리키는 두 수의 합의 절댓값이 가장 작은 것을 고르면 된다.

교차하지 않아도 왼쪽의 포인터가 가리키는 원소가 0보다 크거나 같게 됬을 때 앞으로 양수 + 양수만 나온다.

이와 마찬가지로, 오른쪽의 포인터가 가리키는 원소가 0보다 작거나 같게 됬을 때 앞으로 음수 + 음수만 나온다.

즉, 이 2경우 더 이상 양음수의 조합이 존재하지 않으로 이전의 양음수의 조합에서 답이 되는 절댓값이 가장 작은 경우가 나오므로 반복을 종료한다.

 

 

 

CODE

#include <iostream>
#include <vector>
#include <algorithm>
#define INF 2000*1000*1000
using namespace std;

vector<int> answer(2);
int main() {
    int N;
    cin >> N;
    vector<int> arr(N);
    for (int i = 0; i < N; ++i) cin >> arr[i];
    sort(arr.begin(), arr.end());    //오름차순 정렬

    int start = 0; // start 은 왼쪽 끝에서
    int end = N - 1; // end 은 오른쪽 끝에서 시작
    int min = INF; // 현재까지 절댓값이 가장 작은 합

    while (start < end) {
        int sum = arr[start] + arr[end];

        if (min > abs(sum)) {
            min = abs(sum);
            answer[0] = arr[start];
            answer[1] = arr[end]; 

            if (sum == 0) break;    //절댓값 크기 0인 거 아무거나 뽑으면 되니 0이면 더 이상 확인 불필요.
            
            
            //두 선 중간에 있는 코드는 while문 바깥에 두는 게 직관적이지만 이해하기 어렵지 않아서 코드를 짧게 작성하다 보니 여기에 두었다.
            ////////////////////////////////////////////////////////////////////////////////////////////
            if( arr[0] >=0 ) {    //수열의 모든 수가 양수이면 arr[0]과 arr[1]의 합의 절댓값이 가장 작다.
                answer[1] = arr[1];
                break;
            } else if ( arr[N - 1] <= 0) {    //수열의 모든 수가 음수이면 arr[N - 2]과 arr[N - 1]의 합의 절댓값이 가장 작다.
                answer[0] = arr[N - 2];
                break;
            }
            ///////////////////////////////////////////////////////////////////////////////////////////
            
            
            
            if(arr[start] >=0 || arr[end] <= 0) break;    
            //수열의 수가 양음수 섞여 있을 때, 
            //arr[start] >= 0이면 앞으로 두 수의 합은 양수 + 양수이므로 이전의 음수 + 양수의 합의 절댓값이 가장 작다.
            //arr[end] <= 0이면 앞으로 두 수의 합은 음수 + 음수이므로 이전의 음수 + 양수의 합의 절댓값이 가장 작다.


        }

        if (sum < 0) start++;    //합이 0보다 작으면 음의 수의 크기를 줄이고
        else end--;    //합이 0보다 크면 양의 수의 크기를 줄임.

    }
   
    cout << answer[0] << " " << answer[1];
}

 

반응형

'백준BOJ > 정렬, 투 포인터' 카테고리의 다른 글

백준 1644 소수의 연속합  (0) 2022.07.06
백준 1806 부분합  (0) 2022.07.05
백준 3273 두 수의 합  (0) 2022.07.04
백준 18870 좌표 압축  (0) 2022.06.04
백준 10814 나이순 정렬  (0) 2022.06.04

댓글