[ 백준 ] 7571 / 점 모으기

金弘均·2021년 9월 16일
0

Baekjoon Online Judge

목록 보기
218/228
post-thumbnail

# Appreciation

/*
 * Problem :: 7571 / 점 모으기
 *
 * Kind :: Math
 *
 * Insight
 * - x1, x2, x3, ..., xn 이라는 수열이 있다고 가정하자
 *   이때, |x1-a| + |x2-a| + ... + |xn-a| 가 최소가 되는
 *   a 를 어떻게 구할 수 있을까?
 *   + 결론부터 말하자면 위의 a 는 수열의 중앙값이다
 *     n=홀수=2m-1, a=x[m]
 *     n=짝수=2m,   a=x[m] or x[m+1]
 *     # 이를 수학적으로 증명한 것은 다음의 사이트를 참고하였다
 *       https://hsm-edu.tistory.com/947
 *
 * Point
 * - 평균이 아니라 중앙값을 구해야 한다는 것은 몇 번의 실험을 통해 알 수 있었다
 *   + 1 2 4 98 99 라는 수열이 있다고 하자
 *     # 평균 : 51
 *       50 + 49 + 47 + 47 + 48 = 241
 *     # 중앙값 : 4
 *       3 + 2 + 0 + 94 + 95 = 194
 *       -> xk <= a <= x(k+1) 이라고 하면
 *          수열에서 a 왼쪽 및 오른쪽에 수가 몇 개 있는지가 중요하다
 *          a 의 왼쪽에 수가 2개, 오른쪽에 수가 4개 있다고 하면
 *          a 가 오른쪽으로 한칸 이동하는 경우
 *          왼쪽에 있는 수들은 a 까지의 거리가 한칸 늘어나고
 *          오른쪽에 있는 수들은 a 까지의 거리가 한칸 줄어들게 된다
 *          따라서 a 의 왼쪽에 있는 수와 오른쪽에 있는 수의 개수가 같아야지
 *          각 수에서 a 까지의 거리 합이 최소가 될 수 있다
 */

# Code

//
//  BOJ
//  ver.C++
//
//  Created by GGlifer
//
//  Open Source

#include <iostream>
#include <vector>
#include <algorithm>

using namespace std;

#define endl '\n'

// Set up : Global Variables
/* None */

// Set up : Functions Declaration
/* None */


int main()
{
    // Set up : I/O
    ios::sync_with_stdio(false);
    cin.tie(nullptr);

    // Set up : Input
    int N, M;
    cin >> N >> M;
    vector<int> Y(M), X(M); /* 행 번호, 열 번호를 저장하는 Vector */
    for (int i=0; i<M; i++)
        cin >> X[i] >> Y[i];

    // Process
    sort(Y.begin(), Y.end());
    sort(X.begin(), X.end());
    int ans = 0, my = Y[M/2], mx = X[M/2]; /* my = 행 번호 중앙값, mx = 열 번호 중앙값 */
    for (int y : Y) {
        ans += abs(my-y); /* 행 이동 */
    }
    for (int x : X) {
        ans += abs(mx-x); /* 열 이동 */
    }

    // Control : Output
    cout << ans << endl;
}

// Helper Functions
/* None */
profile
이런 미친 게임을 봤나! - 옥냥이

0개의 댓글