※ 글쓴이는 취미로 코딩을 익혀보는 사람이라 정확하지 않은 내용을 담고 있을 수 있다 ※

 

이번에 볼 문제는 백준 29704번 문제인 벼락치기이다.
문제는 아래 링크를 확인하자.

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

 

29704번: 벼락치기

숙명여자대학교의 알고리즘 학회 ALGOS에 합격한 혜민이는 너무 기뻐 마음이 들뜬 나머지 프로그래밍 과제가 있는 것을 잊어버리고 말았다. 프로그래밍 과제로는 다양한 난이도의 문제 $N$개가

www.acmicpc.net

 

잘 알려진 유형 중 하나인 knapsack dp 문제이다.

 

앞의 i가지 과제만을 고려하여 과제를 t일까지 했을 때 내지 않아도 되게 되는 벌금의 최댓값을 dp[i][t]와 같이 나타내자. i+1번째 과제를 해결하는 데에 드는 시간이 d, 벌금을 w라 할 때 dp는 대략적으로 아래와 같은 식을 만족한다:

dp[i+1][t]=max(dp[i][t],dp[i][td]+w)

 

여기서 dp[i][t]i+1번째 과제를 수행하지 않는 경우를, dp[i][td]+wi+1번째 과제를 수행하는 경우의 내지 않아도 될 벌금의 최댓값을 뜻한다.

 

대략적이라고 언급한 이유는 인덱스가 벗어나는 경우나 초기상태 등을 위에 제대로 언급해두지 않았기 때문이다. 이 부분은 특별할 것이 없으므로(아무 과제도 안 했을 때 dp의 값은 0일 것이다.) 설명을 생략하겠다. 단, 인덱스 등은 구현할 때 범위를 벗어나지 않게끔 신경 써 구현하자.

 

문제의 답은 내지 않아도 될 벌금의 최댓값이 아닌 내야 할 벌금의 최솟값임에 유의하자.

 

아래의 구현은 i의 값이 증가하면 두 단계 전의 i값에 대한 dp의 값을 다시 살펴볼 일이 없다는 점을 이용한 최적화가 포함되어 있다.

 

아래는 제출한 소스코드이다.

#include <iostream>
using namespace std;

int N, T, total;
int dp[1001];
int mx;

int main() {
	ios::sync_with_stdio(0);
	cin.tie(0);

	cin >> N >> T;
	while (N--) {
		int d, w; cin >> d >> w;
		total += w;
		for (int t = T; t >= d; t--) dp[t] = max(dp[t], dp[t - d] + w);
	}

	for (int i = 0; i <= T; i++) mx = max(mx, dp[i]);
	cout << total - mx;
}
728x90

'BOJ' 카테고리의 다른 글

[BOJ 31589 // C++] 포도주 시음  (2) 2024.03.12
[BOJ 28117 // C++] prlong longf  (0) 2024.03.11
[BOJ 26975 // C++] Cow College  (0) 2024.03.09
[BOJ 26596 // C++] 황금 칵테일  (0) 2024.03.08
[BOJ 28446 // C++] 볼링공 찾아주기  (0) 2024.03.07

+ Recent posts