개발하고/코딩테스트

[백준] 1026번 보물

씩씩환 2021. 7. 30. 23:18

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

 

1026번: 보물

첫째 줄에 N이 주어진다. 둘째 줄에는 A에 있는 N개의 수가 순서대로 주어지고, 셋째 줄에는 B에 있는 수가 순서대로 주어진다. N은 50보다 작거나 같은 자연수이고, A와 B의 각 원소는 100보다 작거

www.acmicpc.net

1. 문제 접근

S = A[0]×B[0] + ... + A[N-1]×B[N-1] 식에서 +연산은 교환법칙이 성립하기에 A배열이 재배치가 가능하다는 소리는 B배열 또한 재배치가 가능한 상황과 동일하며 순서에는 재약이 없다는 의미이다. 그렇다면 가장작은 S값을 구하기 위해 A와 B를 어떻게 재배치할지 고민해 보자.

 

우선 A[0]×B[0], A[1]×B[1], ..., A[N-1]×B[N-1] 각각의 값들이 작아야한다. B배열에서 S값에 가장 크게 영향을 줄 값은 B배열이 가진 값들 중 가장 큰 값이며 따라서 이 값을 먼저 고려해보면 A배열에서 가장 작은 값과 곱해져야만 가장 작은 값이 나오게 된다. 마찬가지로 다음으로 고려할 값은 두번째로 S값에 크게 영향을 미칠 값이며 이는 B배열의 값들 중 두번째로 큰 값일테고 A배열에서 두번째로 작은 값과 곱해져야 한다. 이런방식으로 B배열이 끝날때까지 진행하면 가장 작은 S값을 얻을 수 있을 것이다.

 

이를 위해 B배열을 내림차순(3,2,1)으로 정렬시키고 A배열을 오름차순(1,2,3)으로 정렬시켜 같은 인텍스값을 가지는 값들끼리 곱한뒤 그들의 합을 S로 두면 답이 될 것이다.

 

시간복잡도 계산

A, B배열을 정렬하는 연산과, 같은 인덱싱값들끼리 곱하여 더하는 연산을 고려해보면 아래와 같이 시간복잡도를 계산할 수 있다. 이때 N의 최댓값은 고작 50이라고 하였으니 굳이 횟수로 계산해보면 5050번이 되고 이는 주어진 시간 2초를 고려하였을때 차고 넘치는 횟수 이다. 따라서 굳이 시간복잡도가 더 좋은 정렬연산방법도 고려할 필요가 없어 보인다.

시간복잡도 = O(N^2) + O(N^2) + O(N) ≒ 5050

 

 

 

2. 코드

#include<iostream>
using namespace std;

#define MAX_N 50

int descend(int a, int b) {
    return a - b;
}

int ascend(int a, int b) {
    return b - a;
}

void insertSort(int arr[], int arrLen, int(*compare)(int, int)) {
    for (int i = 0; i < arrLen; i++) {
        int maxIdx = i;
        for (int j = i; j < arrLen; j++) {
            if (compare(arr[maxIdx], arr[j]) < 0)
                maxIdx = j;
        }
        int temp = arr[maxIdx];
        arr[maxIdx] = arr[i];
        arr[i] = temp;
    }
}

int main() {
    int N;
    int A[MAX_N];
    int B[MAX_N];
    int answer = 0;

    cin >> N;
    for (int i = 0; i < N; i++)
        cin >> A[i];
    for (int i = 0; i < N; i++)
        cin >> B[i];

    insertSort(A, N, ascend);       // A 오름차순
    insertSort(B, N, descend);      // B 내림차순

    for (int i = 0; i < N; i++)
        answer += (A[i] * B[i]);    // 같은 인덱스 값끼리 곱한뒤 이들을 모두 더한다

    cout << answer << endl;

    return 0;
}