알고리즘 공부/백준

[백준] No.2515 - 전시장 (C++, DP)

EVEerNew 2021. 6. 27. 23:02
반응형

문제

 

https://www.acmicpc.net/problem/2515

 

2515번: 전시장

첫째 줄에는 그림의 개수 N (1 ≤ N ≤ 300,000)과 판매가능 그림을 정의하는 1이상의 정수 S가 빈칸을 사이에 두고 주어진다. 다음 이어지는 N개의 줄 각각에는 한 그림의 높이와 가격을 나타내는 정

www.acmicpc.net

 

풀이

 

solved.ac 난이도: Gold 2

 

 

높이 순서로 정렬 후, 해당 그림이 선택될 수 있도록 하는 앞의 그림들 중 가장 높은 그림을 미리 저장해 두자.

이를 저장하는 이유는 다음과 같은 점화식을 구현하기 위해서 이다.

 

dp[idx] idx번째 그림까지를 고려했을 때, 판매 가능한(선택된) 그림의 가격 합의 최대 값이라 고하자.

dp[idx]를 구할 때 두 가지 경우를 고려해 보아야 한다.

 

1. idx 번째 그림을 선택하지 않는 경우

idx번째 그림이 선택되지 않는다면 dp[idx]는 dp[idx-1] 값과 동일하다.

(dp[idx-1]의 값은 idx-1번째 그림까지 고려한 최댓값이다.)

 

2.  idx번째 그림을 선택하는 경우

idx번째 그림의 높이를 H라고 하자. 해당 그림을 선택하기 위해서는 그림 앞에 H - S 이하의 그림만 배치되어야 한다.

H - S 이하의 높이를 가지는 그림들 중 가장 높은 그림을 limit라고 하면 dp[idx]는 다음과 같다.

dp[idx] = dp[limit] + cost

 

따라서 dp[idx]는 1번(idx번째 그림은 건너뜀)과 2번(idx번째 그림을 선택)의 경우 중 더 큰 값이 된다.

dp[idx] = max( dp[idx-1], dp[limit] + cost )

 

 

이러한 구현을 위해서 limit[idx]에 idx번째 그림이 선택될 수 있도록 하는 앞의 그림들 중 가장 높은 것을 미리 저장하자.

 

1
2
3
4
5
6
for(int idx=1; idx<=picture_num ; ++idx){
  for(limit[idx] = limit[idx-1]; limit[idx] <idx ; ++limit[idx])
    if(pictures[idx].height - pictures[limit[idx]].height < S) 
      break;
  --limit[idx];
}
cs

 

S의 값은 항상 모든 그림의 높이보다 작거나 같으므로

limit[idx-1]의 값에서 다음 그림들을 선택해보아 높이의 차가 S보다 작아지는 경우의 이전 그림이 limit[idx]의 값이 된다.

 

 

 

 

코드

 

#include<iostream>
#include<vector>
#include<string.h>
#include<algorithm>
using namespace std;
int picture_num, selling_height;
vector<int> dp, limit;
vector<pair<int,int>> pictures;
int main(){
ios_base::sync_with_stdio(0);
cin>>picture_num>>selling_height;
dp.resize(picture_num+1);
limit.resize(picture_num+1);
pictures = vector<pair<int,int>>(picture_num+1);
int height, cost;
pictures[0] = {0,0};
for(int i=1; i<=picture_num ; ++i){
cin>>height>>cost;
pictures[i] = {height, cost};
}
sort(pictures.begin(), pictures.end());
for(int idx=1; idx<=picture_num ; ++idx){
for(limit[idx] = limit[idx-1]; limit[idx] <idx ; ++limit[idx])
if(pictures[idx].first - pictures[limit[idx]].first < selling_height) break;
--limit[idx];
}
for(int idx=1; idx<=picture_num ; ++idx)
dp[idx] = max(dp[idx-1], dp[limit[idx]] + pictures[idx].second);
cout<<dp[picture_num]<<'\n';
return 0;
}

 

반응형