포브스 부자 순위 조회 시스템

포브스 잡지는 매년 전 세계 최고 부자들의 순위를 발표합니다. 이 문제에서는 특정 연령대 내에서 가장 부유한 사람들을 찾는 시뮬레이션을 구현해야 합니다. N명의 자산 정보가 주어지면, 각 질의에 대해 지정된 연령 범위 [Amin, Amax] 내에서 자산이 가장 많은 M명을 출력하는 것이 목표입니다.

입력 형식

첫 줄에 사람 수 N과 질의 수 K가 주어집니다. 다음 N줄에는 각각 이름(8자 이하, 공백 없음), 나이(0~200), 자산(정수)이 주어집니다. 마지막 K줄에는 각 질의에 대해 출력할 최대 인원 M, 최소 나이 Amin, 최대 나이 Amax가 주어집니다.

출력 형식

각 질의마다 Case #X:를 먼저 출력하고, 조건을 만족하는 사람들을 다음 순서로 정렬하여 출력합니다:

  1. 자산 내림차순
  2. 자산이 같으면 나이 오름차순
  3. 둘 다 같으면 이름 사전순

해당 인원이 없으면 None을 출력합니다.

최적화 전략

단순히 전체를 정렬 후 매 질의마다 선형 탐색하면 시간 초과가 발생할 수 있습니다. 다음과 같은 접근이 필요합니다:

방법 1: 연령별 인덱싱

각 연령(0~200)에 대해 미리 정렬된 리스트를 만들어두고, 질의 시 해당 범위의 연령들에서 상위 M명을 추출하는 방식입니다.

#include <bits/stdc++.h>
using namespace std;

struct Individual {
    string identity;
    int years;
    int fortune;
};

bool rankingRule(const Individual& x, const Individual& y) {
    if (x.fortune != y.fortune) return x.fortune > y.fortune;
    if (x.years != y.years) return x.years < y.years;
    return x.identity < y.identity;
}

int main() {
    ios::sync_with_stdio(false);
    cin.tie(nullptr);
    
    int totalPeople, queries;
    cin >> totalPeople >> queries;
    
    vector<Individual> database(totalPeople);
    for (int i = 0; i < totalPeople; i++) {
        cin >> database[i].identity >> database[i].years >> database[i].fortune;
    }
    
    sort(database.begin(), database.end(), rankingRule);
    
    // 연령별로 미리 필터링된 벡터 구성 (최대 201개 연령)
    vector<vector<Individual>> ageBuckets(201);
    for (const auto& person : database) {
        ageBuckets[person.years].push_back(person);
    }
    
    for (int q = 1; q <= queries; q++) {
        int limit, minAge, maxAge;
        cin >> limit >> minAge >> maxAge;
        
        cout << "Case #" << q << ":\n";
        
        vector<Individual> candidates;
        // 해당 연령 범위의 모든 사람 수집
        for (int age = minAge; age <= maxAge && candidates.size() < limit * 201; age++) {
            for (const auto& p : ageBuckets[age]) {
                candidates.push_back(p);
                if (candidates.size() > limit * 100) break; // 과도한 메모리 방지
            }
        }
        
        // 이미 전체 정렬되어 있으므로 상위 limit개 출력
        if (candidates.empty()) {
            cout << "None\n";
        } else {
            int outputCount = min(limit, (int)candidates.size());
            for (int i = 0; i < outputCount; i++) {
                cout << candidates[i].identity << " " 
                     << candidates[i].years << " " 
                     << candidates[i].fortune << "\n";
            }
        }
    }
    
    return 0;
}

방법 2: 효율적인 선형 탐색 (통과 가능)

실제로는 전체를 자산순으로 정렬 후, 각 질의마다 선형 탐색하되 조기 종료를 활용하면 통과할 수 있습니다. 핵심은 ios::sync_with_stdio(false)cin.tie(nullptr)로 입출력 최적화하는 것입니다.

#include <bits/stdc++.h>
using namespace std;

struct Entity {
    string label;
    int lifetime;
    int assets;
};

bool priorityOrder(const Entity& first, const Entity& second) {
    if (first.assets != second.assets) 
        return first.assets > second.assets;
    if (first.lifetime != second.lifetime) 
        return first.lifetime < second.lifetime;
    return first.label < second.label;
}

int main() {
    ios::sync_with_stdio(false);
    cin.tie(nullptr);
    
    int population, questionCount;
    cin >> population >> questionCount;
    
    vector<Entity> records(population);
    for (int idx = 0; idx < population; idx++) {
        cin >> records[idx].label >> records[idx].lifetime >> records[idx].assets;
    }
    
    sort(records.begin(), records.end(), priorityOrder);
    
    for (int qIdx = 1; qIdx <= questionCount; qIdx++) {
        int maxDisplay, ageLower, ageUpper;
        cin >> maxDisplay >> ageLower >> ageUpper;
        
        cout << "Case #" << qIdx << ":\n";
        
        int found = 0;
        for (const auto& entry : records) {
            if (found >= maxDisplay) break;
            if (entry.lifetime >= ageLower && entry.lifetime <= ageUpper) {
                cout << entry.label << " " 
                     << entry.lifetime << " " 
                     << entry.assets << "\n";
                found++;
            }
        }
        
        if (found == 0) {
            cout << "None\n";
        }
    }
    
    return 0;
}

주의사항

  • printf/scanf 대신 cin/cout을 쓸 때는 반드시 입출력 동기화를 끄세요
  • 벡터의 insert는 O(n)이므로 범위 삽입 시 주의
  • 각 연령당 최대 100명만 저장하는 최적화도 고려 가능

태그: C++ algorithm sorting Binary Search STL

9월 13일 06:50에 게시됨