선행지식

map

문제

국민대학교에서는 매 학기 시작 전 종합정보시스템에서 수강신청을 한다. 매 수강신청마다 아주 많은 학생들이 몰려 서버에 많은 부하가 가기 때문에, 국민대학교에서는 수강신청 부하 관리 시스템을 도입하기로 결정하였다. 새로운 관리 시스템은 다음과 같은 방식으로 동작한다.

  1. 수강신청 버튼이 활성화 된 후, 수강신청 버튼을 조금이라도 빨리 누른 학생이 대기목록에 먼저 들어간다.
  2. 이미 대기열에 들어가 있는 상태에서 다시 수강신청 버튼을 누를 경우 대기목록의 맨 뒤로 밀려난다.
  3. 잠시 후 수강신청 버튼이 비활성화 되면, 대기목록에서 가장 앞에 있는 학생부터 자동으로 수강신청이 완료되며, 수강 가능 인원이 꽉 찰 경우 나머지 대기목록은 무시하고 수강신청을 종료한다.

ex

위의 표는 최대 수강 가능 인원이 3명인 알고리즘 수업에 대해 6명의 학생이 수강신청을 진행한 모습이다. 버튼이 비활성화 된 후, 먼저 규칙 1을 적용하여 클릭을 2번 이상 한 학생의 중복된 대기목록을 삭제한다. 중복된 목록을 제거한 후, 맨 앞에서부터 최대 수강 가능 인원인 3명을 선정한다. 표의 맨 오른쪽에는 그 최종결과를 나타낸 모습이다. 이와 같은 방법을 이용하여 최종적으로 수강신청에 성공한 인원을 출력하는 프로그램을 작성하시오.

접근방식 1 (vector)

간단하게 vector에서 find를 이용하여 값을 찾을 수 없다면 vector에 값을 넣고, 아니라면 규칙 2에 따라서 전에 입력받은 값을 삭제하고 vector에 값을 넣는다.

#include <iostream>
#include <vector>
#include <algorithm>
using namespace std;
int main(){
    ios_base::sync_with_stdio(false);
    cin.tie(NULL);
    cout.tie(NULL);
    int n,m;
    string x;
    vector<string> a;
    cin >> n >> m;
    while (m--){
        cin >> x;
        auto it=find(a.begin(),a.end(),x);
        if(it==a.end()){
            a.push_back(x);
        }else{
            a.erase(a.begin()+(it-a.begin()));
            a.push_back(x);
        }
    }for(auto i=a.begin(); i!=a.begin()+n; i++){
        cout << *i << '\n';
    }
}

간단하지만 역시… 시간초과가 나왔다.
삭제가 느려서 그런 것 같았다.

접근방식 2 (unordered_map)

이번에는 map에 저장하고 그 저장한 값과 index를 vector에 저장하고 index에 따라 정렬을 한 후에 출력한다.

#include <iostream>
#include <vector>
#include <algorithm>
#include <unordered_map>
using namespace std;
bool cmp(pair<string, int>& a, pair<string, int>& b){
    return a.second < b.second;
}
int main(){
    ios_base::sync_with_stdio(false);
    cin.tie(NULL);
    cout.tie(NULL);
    int n,m,cnt=0;
    string x;
    unordered_map<string, int> a;
    cin >> n >> m;
    for(int i=0; i<m; i++){
        cin >> x;
        if(a.find(x)!=a.end()){
            a.erase(x);
            a.insert({x,i});
        }else{
            a.insert({x,i});
        }
    }vector<pair<string, int>> v(a.begin(), a.end());
    sort(v.begin(), v.end(), cmp);
    for(auto i : v){
        if(cnt==n)break;
        cnt++;
        cout << i.first << '\n';
    }
}