백준 7662번: 이중 우선순위 큐/multiset이용

Jimin·2022년 7월 25일
0

알고리즘

목록 보기
23/71

문제

이중 우선순위 큐(dual priority queue)는 전형적인 우선순위 큐처럼 데이터를 삽입, 삭제할 수 있는 자료 구조이다. 전형적인 큐와의 차이점은 데이터를 삭제할 때 연산(operation) 명령에 따라 우선순위가 가장 높은 데이터 또는 가장 낮은 데이터 중 하나를 삭제하는 점이다. 이중 우선순위 큐를 위해선 두 가지 연산이 사용되는데, 하나는 데이터를 삽입하는 연산이고 다른 하나는 데이터를 삭제하는 연산이다. 데이터를 삭제하는 연산은 또 두 가지로 구분되는데 하나는 우선순위가 가장 높은 것을 삭제하기 위한 것이고 다른 하나는 우선순위가 가장 낮은 것을 삭제하기 위한 것이다.

정수만 저장하는 이중 우선순위 큐 Q가 있다고 가정하자. Q에 저장된 각 정수의 값 자체를 우선순위라고 간주하자.

Q에 적용될 일련의 연산이 주어질 때 이를 처리한 후 최종적으로 Q에 저장된 데이터 중 최댓값과 최솟값을 출력하는 프로그램을 작성하라.


입력

입력 데이터는 표준입력을 사용한다. 입력은 T개의 테스트 데이터로 구성된다. 입력의 첫 번째 줄에는 입력 데이터의 수를 나타내는 정수 T가 주어진다. 각 테스트 데이터의 첫째 줄에는 Q에 적용할 연산의 개수를 나타내는 정수 k (k ≤ 1,000,000)가 주어진다. 이어지는 k 줄 각각엔 연산을 나타내는 문자(‘D’ 또는 ‘I’)와 정수 n이 주어진다. ‘I n’은 정수 n을 Q에 삽입하는 연산을 의미한다. 동일한 정수가 삽입될 수 있음을 참고하기 바란다. ‘D 1’는 Q에서 최댓값을 삭제하는 연산을 의미하며, ‘D -1’는 Q 에서 최솟값을 삭제하는 연산을 의미한다. 최댓값(최솟값)을 삭제하는 연산에서 최댓값(최솟값)이 둘 이상인 경우, 하나만 삭제됨을 유념하기 바란다.

만약 Q가 비어있는데 적용할 연산이 ‘D’라면 이 연산은 무시해도 좋다. Q에 저장될 모든 정수는 32-비트 정수이다.


출력

출력은 표준출력을 사용한다. 각 테스트 데이터에 대해, 모든 연산을 처리한 후 Q에 남아 있는 값 중 최댓값과 최솟값을 출력하라. 두 값은 한 줄에 출력하되 하나의 공백으로 구분하라. 만약 Q가 비어있다면 ‘EMPTY’를 출력하라.


#define _CRT_SECURE_NO_WARNINGS
#include <iostream>
#include <vector>
#include <map>
#include <queue>
#include <algorithm>
#include <string>
#include <set>
using namespace std;

int T; // 입력데이터의 수
int k; // 최대 1000000, Q에 적용할 연산의 개수


int main() {
    cin >> T;
    while (T--) {
        cin >> k; // 연산 횟수
        char op; // 연산을 나타내는 문자 D 또는 I
        int n;
        multiset<int> Q;
        while(k--) {
            cin >> op >> n;
            if (op == 'I') {
                // Q에 n 삽입
                Q.insert(n);
            }
            else if (op == 'D') {
                if (Q.empty())continue;
                if (n == 1) {
                    // Q에서 최대값 삭제
                    auto E = Q.end();
                    E--;
                    Q.erase(E);
                }
                else if (n == -1) {
                    // Q에서 최솟값 삭제
                    Q.erase(Q.begin());
                }
            }
        }
        if (Q.empty()) {
            cout << "EMPTY\n";
        }
        else {
            auto E = Q.end();
            E--;
            cout << *E << " " << *(Q.begin()) << "\n";
        }
    }
    
    return 0;
}

우선 순위 큐 자체에서 최대값 최소값 찾기가 어려운 것 같아서 구글링해서 multiset이라는 개념을 찾았다.

multiset을 이용하면 간단하게 해결된다.

multiset

헤더 설정 및 구현

#include <set>

multiset<int> ms;
  • 트리 자료구조

  • multiset에 원소를 넣으면 자동으로 오름차순 정렬이 된다.

  • 중위 순회로 원소에 접근한다. (중위 순회는 트리에서 루트 노드를 중간 순서에 방문 하는 순회)

  • insert() 함수를 통해 원소를 삽입한다.

  • erase() 함수를 통해 원소를 삭제할 수 있다. → erase 함수 안에 인자로 값을 직접 넣으면 해당 값을 가진 모든 원소가 삭제된다. 하지만, 주소 값을 넣으면 그 주소에 해당 하는 원소만 삭제된다.

multiset<int> ms;
ms.insert(3); // multiset에 3 삽입 {3}
ms.insert(4); // multiset에 3 삽입 {3,4}

ms.erase(ms.begin()); // multiset에서 시작 값(최소값) 삭제 {4}
  • begin(), end() 함수를 통해 가장 작은 값과 가장 큰 값의 주소값을 얻을 수 있다.

  • 하지만 end()는 끝 원소의 다음 주소를 반환하므로 진짜 끝 원소의 주소값을 얻기 위해서는 주소에 -1을 해주어야한다.

  • 실제 값은 주소에 *을 붙여서 얻을 수 있다!

int min,max;
min = *ms.begin();
auto iter = ms.end(); //반복자 생성
iter--; // end는 원소 끝 다음의 주소를 반환하므로 1을 빼준다.
max = *iter;
profile
https://github.com/Dingadung

0개의 댓글