알고리즘/BOJ

백준 2473번 : 세 용액 (C++)

DOWN 2021. 7. 13. 21:42

문제 : https://www.acmicpc.net/problem/2473

 

2473번: 세 용액

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

www.acmicpc.net

 

정수 배열에서 3개의 수를 골라 그 3개의 합이 최대한 0에 가까운 조합을 찾는문제이다. 먼저 N의 범위를 보자. N의 범위는 5000이하인 수로 O(N^2) 방법으로 시간내 풀 수 있음을 추측가능하다.

만약 골라야 하는 수가 3개가 아니고 2개라면 투 포인터나 해쉬맵으로 쉽게 해결할 수 있을 것이다.  그런 경우에는 배열의 사전에 정렬해줘야하므로 O(NlogN + N)의 복잡도를 가진다. 그럼 만약 골라야하는 수 1개는 고정시켜두고 나머지에 대해서만 투 투인터 방법을 사용하는것은 어떨까? 즉 3번째 수를 일단 골랐다고 하면 4번째수 ~ N번째 수에 대해서만 투 포인터로 타겟들을 찾는것이다. 그럼 시간복잡도가 O(NlogN + N^2) = O(N^2)으로 시간내에 충분히 풀 수 있다.

 

 

 

	#include <iostream>
	#include <vector>
	#include <algorithm>
	#include <cmath>
	#include <set>
	#include<map>
	#include <queue>

	typedef long long ll;

	using namespace std;
	int n;
	ll p[100002];


	int main()
	{
		cin.tie(NULL);
		ios::sync_with_stdio(false);
		
		cin >> n;

		for(int i=1; i<=n; i++){
			cin >> p[i];
		}

		
		sort(&p[1], &p[n+1]);

		ll sum = INT64_MAX;
		ll a1, a2, a3;
		for(int i=1; i<=n; i++){
			int j = i+1;
			int k = n;
			while(j < k){
				if(sum > abs(p[i] + p[j] + p[k])){
					sum = abs(p[i] + p[j] + p[k]);
					a1 = p[i];
					a2 = p[j];
					a3 = p[k];
				}

				if(p[i] + p[j] + p[k] < 0){
					j++;
				}
				else{
					k--;
				}
			}
		}

		cout << a1 << ' ' << a2 << ' ' << a3;
	}