• [백준OJ] 9007번 카누 선수

    2021. 5. 20.

    by. Hyeon-Uk

    반응형

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

     

    9007번: 카누 선수

    이 문제에서는 입력은 표준 입력을 사용한다. 입력의 첫 줄에는 T개의 테스트 케이스가 주어진다. 각 테스트 케이스에는 두 개의 정수 k와 n이 주어지며, k( 1 ≤ k ≤ 40,000,000)는 보트의 특정 값 그

    www.acmicpc.net


     

    -풀이-

    4개 각각의 조합을 맞춰가며 최솟값을 찾으면 O(N4)이라는 어마어마한 시간이 걸리기 때문에, 다른 방법을 생각해보았다.

    1. 먼저 클래스 1,2에서 나올 수 있는 합의 경우를 모두 v1에, 클래스 3,4에서 나올 수 있는 합의 경우를 모두 v2에 push_back한다.

    2. 그런 뒤 v1,v2를 정렬한다.

    3. v1의 첫번째 원소부터 탐색을 한다. 구해야하는 K와 v1의 탐색중인 원소의 차이를 D라고 하면, v2에서 lower_bound를 이용해서 D보다 크거나 같은 수 중에서 가장 작은 수를 구해준다.

    4. 3번에서 구한 결과와 v1에서 탐색중인 원소의 값을 더해주며, K와 근접하다면 갱신해준다. 단. K와의 차이의 절댓값이 같다면 4명의 학생의 합이 작은 수를 구해야 하므로 , 갱신을 할때 조건을 추가해준다.

    5. lower_bound의 특성상 크거나 같은수중 가장 작은수를 구하는 함수이므로 , 3번에서 구한 lower_bound의 인덱스보다 한칸 작은칸의 원소도 검사를 해주어야한다.

    예를들어

    현재 탐색하는 v1의 원소 = 5, 구하고싶은 K의 값 = 10, v2= { 1,2,3,4,50,60,70,} 이라고 한다면,

    D의 값은 10-5 = 5가 된다. 이때 lower_bound를 한다면, 50이 결과로 나오게 된다.

    1.) v1의 원소+lower_bound로 구한 값 = 5+50 = 55가 되므로, K와의 차이가 45가 나게된다.

    2) v1의 원소 + lower_bound로 구한 인덱스-1번째 값 = 5+4 = 9가 되므로, K와의 차이가 1이 나게된다.

     

    이처럼 lower_bound로 구한 인덱스의 값만 검사하는게아니라, 한칸 이전의 원소도 검사를 해주어야 정확한 결과가 나온다.

     

    -시간복잡도-

    v1,v2에 모든 합의 경우를 넣는 로직 O(N2)

    v1,v2 정렬 = O(N2logN)

    결과값 구하는 로직 =O(N2logN)

     

    따라서 총 시간복잡도는 O(N2logN)이 된다.

     

    -코드-

     

    #include<iostream>
    #include<algorithm>
    #include<vector>
    #include<cmath>
    #include<limits.h>
    #define INF INT_MAX;
    using namespace std;
    
    int arr1[1000], arr2[1000];
    vector<int> v1, v2, v3;
    int t, n, m;
    
    int main() {
    	ios_base::sync_with_stdio(false);
    	cin.tie(NULL);
    	cout.tie(NULL);
    	
    	cin >> t;
    	while (t--) {
    		v1.clear();
    		v2.clear();
    		int n, m;
    		cin >> m >> n;
    		for (int i = 0; i < n; i++) {
    			cin >> arr1[i];
    		}
    		for (int i = 0; i < n; i++) {
    			cin >> arr2[i];
    		}
    		for (int i = 0; i < n; i++) {
    			for (int j = 0; j < n; j++) {
    				v1.push_back(arr1[i] + arr2[j]);
    			}
    		}
    
    		for (int i = 0; i < n; i++) {
    			cin >> arr1[i];
    		}
    		for (int i = 0; i < n; i++) {
    			cin >> arr2[i];
    		}
    		for (int i = 0; i < n; i++) {
    			for (int j = 0; j < n; j++) {
    				v2.push_back(arr1[i] + arr2[j]);
    			}
    		}
    		sort(v1.begin(), v1.end());
    		sort(v2.begin(), v2.end());
    
    		int result, gap;
    		result = gap = INF;
    		for (int i = 0; i < n*n; i++) {
    			int val = m - v1[i];
    			int ind = lower_bound(v2.begin(), v2.end(), val) - v2.begin();
    			if (ind == n * n) ind--;
    			int total = v1[i] + v2[ind];
    			int tgap = abs(m - total);
    			if (gap == tgap && result > total) {
    				result = total;
    			}
    			else if (gap > tgap) {
    				gap = tgap;
    				result = total;
    			}
    			if (ind != 0) {
    				total = v1[i] + v2[ind - 1];
    				tgap = abs(m - total);
    				if (gap == tgap && result > total) {
    					result = total;
    				}
    				else if (gap > tgap) {
    					gap = tgap;
    					result = total;
    				}
    			}
    		}
    		cout << result << "\n";
    	}
    	return 0;
    }
    
    반응형

    '문제풀이 > 백준oj' 카테고리의 다른 글

    [백준OJ] 11724번 연결 요소의 개수  (0) 2021.05.28
    [백준OJ] 1439번 뒤집기  (0) 2021.05.21
    [백준OJ] 2268번 수들의 합  (0) 2021.05.19
    [백준OJ] 얼음깨기 펭귄  (2) 2021.05.18
    [백준OJ] 1956번 운동  (0) 2021.05.07

    댓글