[BOJ/C++] 2295 세 수의 합

Flame🔥·2023년 11월 2일
0

BOJ

목록 보기
9/11
post-thumbnail

문제 링크

문제
N(5 ≤ N ≤ 1,000)개의 자연수들로 이루어진 집합 U가 있다. 이 중에서 적당히 세 수를 골랐을 때, 그 세 수의 합 d도 U안에 포함되는 경우가 있을 수 있다. 이러한 경우들 중에서, 가장 큰 d를 찾으라.

예를 들어 {2, 3, 5, 10, 18}와 같은 집합이 있다고 하자. 2+3+5 = 10이 되고, 이 수는 집합에 포함된다. 하지만 3+5+10 = 18이 되고, 이 경우가 세 수의 합이 가장 커지는 경우이다.

입력
첫째 줄에 자연수 N이 주어진다. 다음 N개의 줄에 차례로 U의 원소가 하나씩 주어진다. 주어진 U는 집합이 되므로 입력되는 두 수가 같아서는 안 된다. U의 원소는 200,000,000보다 작거나 같은 자연수이다. 답이 항상 존재하는 경우만 입력으로 주어진다.

출력
우리가 x번째 수, y번째 수, z번째 수를 더해서 k번째 수를 만들었다라고 하자. 위의 예제에서 2+3+5=10의 경우는 x, y, z, k가 차례로 1, 2, 3, 4가 되며, 최적해의 경우는 2, 3, 4, 5가 된다. k번째 수가 최대가 되도록 하는 것이 목적이다. x, y, z, k가 서로 같아도 된다. 이때, k번째 수를 출력하면 된다.

예제 입력 1
5
2
3
5
10
18
예제 출력 1
18

문제 정리

  • 4중 for문을 돌려 A[i]+A[j]+A[k] = A[l]
    을 확인하는 방법을 떠올릴 수 있다. 하지만 시간 복잡도가 O(n⁴)이다. n이 최대 1000이고 시간 제한이 1초이다. 약 1억에 1초이므로 O(n³)을 넘기면 안된다.

  • 3중 for문을 돌려 A[i]+A[j]+A[k]을 구하고 이분 탐색을 통해 A[l]을 찾는 방법도 시간 복잡도는 O(N³logN)로 O(n³)을 넘긴다.

  • 2중 for문을 돌려 A[i]+A[j]를 구하고 이분 탐색을 통해 A[l]-A[k]를 구한다 -> 시간복잡도 O(N²logN)

이분 탐색 알고리즘

A[i] + A[j] = A[l] - A[k]를 만족하는 A[l]의 최댓값을 구하는 것이다.

구현 코드

#include <bits/stdc++.h>

using namespace std;

int A[1001];


int main()
{
    cin.tie(0);
    ios::sync_with_stdio(0);

    vector <int> two;

    int n;
    cin >> n;
    for(int i=0; i<n; i++)
        cin >> A[i];
    sort(A,A+n);

	//먼저 2중 for문으로 두 수의 합을 구한 뒤 백터에 넣는다
    for(int i=0; i<n; i++)
    {
        for(int j=0; j<n; j++)
            two.push_back(A[i]+A[j]);
    }
    
    //이분 탐색 수행을 위해 정렬한다
    sort(two.begin(), two.end());
   
   //세 수의 합을 가장 크게 하기 위해 i를 배열의 마지막 원소로 설정한다
    for(int i=n-1; i>=0; i--)
    {
        for(int j=0; j < i ; j++)
        {
            if (binary_search(two.begin(),two.end(),A[i]-A[j]))
            { 
                cout << A[i];
                return 0;
            }
        }
    }

두 번째 2중 for문을 살펴보자. 우리는 세 수의 합이 가장 큰 경우를 구해야 한다. 세 수의 합은 A[i]이고 A[i]가 가장 큰 경우를 구하는 것이므로 i = n-1로 설정한 것을 볼 수 있다.

참고 https://blog.encrypted.gg/985

profile
숭실대학교 컴퓨터학부 22

0개의 댓글