Problem 1202
보석 도둑
문제
세계적인 도둑 상덕이는 보석점을 털기로 결심했다.
상덕이가 털 보석점에는 보석이 총 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)
모든 숫자는 양의 정수이다.
출력
첫째 줄에 상덕이가 훔칠 수 있는 보석 가격의 합의 최댓값을 출력한다.
문제 링크
https://www.acmicpc.net/problem/1202
예제 입력 1
3 2
1 65
5 23
2 99
10
2
예제 출력 1
164
solve
그리디 알고리즘으로 무게 제한이 작은 가방에 비싼 보석을 먼저 담아야 최대로 보석을 가져갈 수 있다.
보석을 가격이 비싼 순으로 정렬하고, 가방을 무게 제한이 낮은 순으로 정렬한다.
- 이후 가격이 비싸고 가방에 담을 수 있는 순으로 모든 경우를 확인하며 계산하니 시간 초과가 발생한다.
- O(nk)라는 시간 복잡도를 갖는데, 이것은 300000*300000 이므로 1억을 넘는다.
그래서 우선순위 큐를 사용하였다.
- 보석과 가방 모두 무게를 기준으로 오름차순으로 정렬을 하고
- 가방을 하나씩 확인하며 i번째 가방의 무게보다 작거나 같은 보석을 모두 우선순위 큐에 push한다.
- 현재 우선순위 큐의 top()값(가장 비싼 보석의 가격)을 누적하고 pop()을한다.
이렇게 진행하면 매번 모든 보석을 확인하지 않고, 한번 큐에 넣은 보석은 다시 확인하지 않아도 된다.
따라서, 보석을 한 번씩만 확인하고 현재 가장 가벼운 가방에 들어갈 수 있는 가방 비싼 보석을 찾을 수 있다.
코드 설명
처음 작성한 코드이다. 시간복잡도 O(nk)로 시간 초과가 발생했다.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
using namespace std;
const int MAX = 300000;
struct gem
{
int weight, price;
};
bool compare(gem u, gem v)
{
if (u.price == v.price) return u.weight < v.weight; // 가격이 같다면 무게가 작은 순서로
else return u.price > v.price; // 가격에 대해 내림차순
}
int main(void)
{
int n, k; // 보석의 개수, 가방의 개수
cin >> n >> k;
vector<gem> a(n);
vector<int> c(k); // 가방의 최대 무게
for (int i = 0; i < n; i++)
cin >> a[i].weight >> a[i].price;
for (int i = 0; i < k; i++)
cin >> c[i];
sort(a.begin(), a.end(), compare); // 가격이 비싼 순, 같다면 무게가 낮은 순
sort(c.begin(), c.end()); // 가벼운 가방 순
long long ans = 0;
for (int i = 0; i < k; i++)
{
for (int j = 0; j < n; j++)
{
if (a[j].weight <= c[i])
{
ans += a[j].price;
a[j].weight = INT_MAX;
break;
}
}
}
cout << ans << '\n';
}우선순위 큐 사용
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
using namespace std;
const int MAX = 300000;
struct gem
{
int weight, price;
};
bool compare(gem u, gem v)
{
return u.weight < v.weight; // 무게에 대해 오름차순
}
int main(void)
{
int n, k; // 보석의 개수, 가방의 개수
cin >> n >> k;
vector<gem> a(n);
vector<int> c(k); // 가방의 최대 무게
for (int i = 0; i < n; i++)
cin >> a[i].weight >> a[i].price;
for (int i = 0; i < k; i++)
cin >> c[i];
sort(a.begin(), a.end(), compare); // 무게가 가벼운 순
sort(c.begin(), c.end()); // 가벼운 가방 순
priority_queue <int> pq; // 최대 힙
int gemidx = 0; // 보석의 인덱스
long long ans = 0;
for (int i = 0; i < k; i++)
{
while (gemidx < n && c[i] >= a[gemidx].weight) // 보석을 한번씩만 확인하기 위해 gemidx사용
{ // i번째 가방의 무게보다 작거나 같은 보석을 모두 우선순위 큐에 삽입
pq.push(a[gemidx++].price);
}
if (!pq.empty())
{
ans += (long long)pq.top(); // 가장위 (최댓값을 누적)
pq.pop();
}
}
cout << ans << '\n';
}