수학, 알고리즘

[백준][자료구조]보석 도둑

춤추는수달 2022. 7. 20. 12:45

문제

세계적인 도둑 상덕이는 보석점을 털기로 결심했다.

상덕이가 털 보석점에는 보석이 총 N개 있다. 각 보석은 무게 Mi와 가격 Vi를 가지고 있다. 상덕이는 가방을 K개 가지고 있고, 각 가방에 담을 수 있는 최대 무게는 Ci이다. 가방에는 최대 한 개의 보석만 넣을 수 있다.

상덕이가 훔칠 수 있는 보석의 최대 가격을 구하는 프로그램을 작성하시오.

입력

첫째 줄에 N과 K가 주어진다. (1 ≤ N, K ≤ 300,000)

다음 N개 줄에는 각 보석의 정보 Mi와 Vi가 주어진다. (0 ≤ Mi, Vi ≤ 1,000,000)

다음 K개 줄에는 가방에 담을 수 있는 최대 무게 Ci가 주어진다. (1 ≤ Ci ≤ 100,000,000)

모든 숫자는 양의 정수이다.

출력

첫째 줄에 상덕이가 훔칠 수 있는 보석 가격의 합의 최댓값을 출력한다.

예제 입력 1

2 1
5 10
100 100
11

예제 출력 1

10

예제 입력 2

3 2
1 65
5 23
2 99
10
2

예제 출력 2

164

원리

보석 목록과 가방 목록을 무게 순으로 정렬한 뒤, 모든 가방들을 순회하면서 그 가방의 용량보다 작은 보석들만 우선순위 큐에 넣고 하나 씩 pop하면 된다.

요점은 보석 목록을 한 번만 순회하는 것.

시행착오

처음엔 가방을 순회할 때 마다 매번 가방에 들어갈 수 있는 보석들을 전부 순회해서 그중 가장 큰 값을 구하려고 했다.

그러나 보석들을 한 번씩만 확인해도 가능한 문제였음을 알았다.

풀이

#include <iostream>
#include <vector>
#include <algorithm>
#include <queue>
using namespace std;

int main() {
	ios_base::sync_with_stdio(0);

	cin.tie(0);

	int N, K;
	cin >> N >> K;
	vector<pair<int, int>> gems;
	vector<int> bags;
	priority_queue<int> pq;
	long long sum = 0;
	for (size_t i = 0; i < N; i++)
	{
		int m, v;
		cin >> m >> v;
		gems.push_back(pair<int, int>(m, v));
	}

	for (size_t i = 0; i < K; i++)
	{
		int c;
		cin >> c;
		bags.push_back(c);

	}
	sort(gems.begin(), gems.end());
	sort(bags.begin(), bags.end());
	//for (iter = gems.begin(); iter != gems.end(); iter++) {
	//	cout << "[" << iter->first << ", " << iter->second << "]" << " ";
	//}
	int idx = 0;
	for (size_t i = 0; i < K; i++)
	{
		/*for (size_t j = idx; j < N; j++)
		{
			if (gems[j].first > bags[i]) break;
			pq.push(gems[i].second);
			idx++;
		}*/
		while (idx < N && gems[idx].first <= bags[i])
		{
			pq.push(gems[idx++].second);
		}
		if (!pq.empty()) {
			sum += pq.top();
			pq.pop();
		}

	}


	cout << sum;
	cin >> N;
}

'수학, 알고리즘' 카테고리의 다른 글

[프로그래머스 Lv3] 셔틀버스  (0) 2022.07.21
[백준][문자열]Startlink Tower  (0) 2022.07.20
[백준][문자열] Contact  (0) 2022.07.20
[백준] ACM Craft  (0) 2022.07.20
[백준] 색종이 만들기  (0) 2022.07.20