[ 백준 ] 2262 / 토너먼트 만들기

金弘均·2021년 9월 16일
0

Baekjoon Online Judge

목록 보기
199/228
post-thumbnail

# Appreciation

/*
 * Problem :: 2262 / 토너먼트 만들기
 *
 * Kind :: Greedy
 *
 * Insight
 * - 예제부터 분석해보자
 *   6
 *   1 6 2 5 3 4
 *   + 랭킹 1은 최대한 다른 선수들과 시합하지 않아야 한다
 *     그리고 어차피 랭킹 2와 시합하게 된다
 *     랭킹 1을 제외하고는 결국 랭킹 2가 다 이기기 때문이다
 *     # 그럼 이렇게 볼 수 있을 것 같다
 *       1 / 6 2 5 3 4
 *       6 2 5 3 4 에서는 랭킹 2가 올라올테니
 *       이는 시합 (1,2) 와 토너먼트 [6 2 5 3 4] 로 나눌 수 있다
 *     # 6 2 5 3 4 도
 *       6 / 2 / 5 3 4
 *       로 나눌 수 있을 것이다
 *       마찬가지로 랭킹 2는 최대한 다른 선수들과 시합하지 않아야 한다
 *       -> 랭킹 2의 왼편에는 랭킹 6밖에 없으니 랭킹 6이 올라올 것이고
 *          랭킹 2의 오른편에는 랭킹이 가장 높은 랭킹 3이 올라올 것이다
 *          즉, 6 / 2 / 5 3 4 는 6 / 2 / 3 이 될 것이다
 *          이는 시합 (6,2), (2,3) 과 토너먼트 [5 3 4] 로 나눌 수 있다
 *     # 5 3 4 도
 *       5 / 3 / 4
 *       -> 시합 (5,3) 과 (3,4) 가 된다
 *       -> 그렇다면 총 열리는 시합은
 *          (1,2) (6,2) (2,3) (5,3) (3,4) 이며
 *          랭킹 차이의 총 합은 9 이다
 *
 * Point
 * - i 번째 선수부터 j 번째 선수까지 있을 때
 *   몇 번째 선수가 가장 랭킹이 높은지 쉽게 알 수 있도록
 *   사전에 그 값을 저장한 배열을 만들어서 활용해주자
 *   + W[i][j] = i 번째 선수부터 j 번째 선수사이의 랭킹이
 *               가장 높은 선수의 인덱스(몇 번째)
 */

# Code

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


#include <iostream>
#include <algorithm>

using namespace std;

#define endl '\n'

// Set up : Global Variables
int N;
int A[256];
int W[256][256];

// Set up : Functions Declaration
int f(int s, int e);


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

    // Set up : Input
    cin >> N;
    for (int i=0; i<N; i++)
        cin >> A[i];

    // Process
    /* W[i][j] = i 번째부터 j 번째가지 선수들 중
     *           가장 랭킹이 높은 선수의 인덱스(몇 번째) */
    for (int i=0; i<N; i++) {
        W[i][i] = i;
        for (int j=i+1; j<N; j++) {
            W[i][j] = (A[W[i][j-1]] > A[j]) ? j : W[i][j-1];
        }
    }

    int ans = f(0, N-1);

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

// Helper Functions
int f(int s, int e)
/* s 번째부터 e 번째까지 선수들의 토너먼를 진행할 시 랭킹 차이의 합의 최솟값을 반환 */
{
    /* 경계조건 */
    if (s >= e) return 0;

    int val = 0; /* 랭킹 차이의 합의 최솟값 */
    int i = W[s][e]; /* s 번째부터 e 번째까지 선수들 중 
                      * 가장 랭킹이 높은 선수의 인덱스(몇 번째) */
    /* i 번째 선수의 왼편 */
    if (i-1 >= s) {
        val += abs(A[i]-A[W[s][i-1]]); /* i 번째 선수는 왼편의 선수들 중
                                        * 가장 랭킹이 높은 선수와 시합함 */
        val += f(s,i-1); /* 왼편의 선수들의 토너먼트를 진행 */
    }
    /* i 번째 선수의 오른편 */
    if (i+1 <= e) {
        val += abs(A[i]-A[W[i+1][e]]); /* i 번째 선수는 오른편의 선수들 중
                                        * 가장 랭킹이 높은 선수와 시합함 */
        val += f(i+1,e); /* 오른편의 선수들의 토너먼트를 진행 */
    }

    return val;
}
profile
이런 미친 게임을 봤나! - 옥냥이

0개의 댓글