https://www.acmicpc.net/problem/29792
29792번: 규칙적인 보스돌이
보스의 체력 $P$의 제한 $2.66 \times 10^{11}$와 드랍하는 메소 $Q$의 제한 $1\,596\,506$은 2023년 8월 10일 업데이트 이전의 가장 많은 체력(카오스 혼테일)과 결정의 가격(노멀 파풀라투스)을 가진 일간 보
www.acmicpc.net
- 접근법
이 문제는 다이나믹 프로그래밍 배낭문제이다. 그러나 캐릭터 1,2,3이 있다고 할 때, 1,2,3마다 dp를 돌려서 마지막 최댓값을 모두 저장해놓고 답을 도출하면 된다.
가장 중요한 건 배낭문제를 잘 이해하고 있느냐는 것이다. 배낭문제를 복기해보자.
최대 10kg 담을 수 있고 물건은
번호 무게 가치
1 4 6
2 2 7
3 5 3
4 6 5
5 8 7
위와 같이 정해져 있다고 하자 . 그리고 배낭문제의 정의에 따라, 2차원 배열을 선언하고 행에는 물건, 열에는 무게를 선언한다.
즉 dp[i][j] = i 번째 물건까지 도달했을 때 j 무게에서의 최대 가치이다.
배낭 문제의 핵심은 한 행씩 채워가고 다음 행은 그 전 행의 메모를 보고 작성하게 된다. 이것을 메모이제이션이라한다.
1번 물건만을 가정한다고 하면 무게가 4가되었을 때 배낭에 넣을 수 있으므로 가치는 6이다. 그리고 이후에는 모두 6일것이다.
이제 2번물건까지를 가정하자. 이제는 2번 물건도 넣을 수 있으므로 2kg까지일 때 7을 넣을 수 있다. 그리고 6kg까지 넣을 수 있을 땐 1,2를 모두 넣을 수 있으니 13이 최대 가치이다.
그리고 이제 점화식을 새워보면
2번행의 6번째 즉, 2번 물건까지 살펴볼 때 6키로까지 담을 경우 최대 가치를 살펴보자.
dp[2][6] = dp[1][2] +가치
이것이 된다.
그리고 더 통찰해보면 dp를 적어나가는 경우의 수는 다음과 같다.
1. 물건을 담을 수 없다.
2. 물건을 담을 수 있다.
위의 케이스는 2번이다. 그리고 담을 수 없다면 한 행의 위와 같다. 그러나 담을 수 있더라도 똑 담는것이 이득이라고 할 수 없다. 만약 2키로의 7가치 3키로의 2가치라면 3키로일 때 2키로 가치를 제거하는것 보다 그대로가는 것이 낫다.
즉
if(담을 수 있다면) dp[i][j] = max( dp[i - 1][j] , dp[i - 1][j - 현재 무게] + 가치)
else dp[i][j] = dp[i - 1][j]
자 이제 이 문제로 다시 돌아와보자.
배낭문제라고 판단되었을 때 가장 중요한 것은 무엇이 무게에 해당하고 무엇이 가치에 해당하느냐이다.
이 문제에서 무게에 해당하는 것은 사냥시간이고 가치는 메소이다.
1번 캐릭터의 공격력이 5라 하고 1번보스가 체력이 213, 메소는 50이라하자. 그렇다면 초당 공격력이 5이므로 사냥시간은 213 / 5 = 43초가 걸릴 것이다.
그러므로 무게는 43
가치는 50이다.
이제 배낭문제와 똑같이 진행하면 된다. 그리고 보스의 체력과 메소의 크기가 int를 벗어나기 때문에 long long으로 선언해줘야한다.
#include <iostream>
#include <map>
#include <vector>
#include <algorithm>
using namespace std;
map<int, long long> dps;
vector<pair<long long, long long>> bossinfo;
vector<long long> answer;
int main() {
ios_base::sync_with_stdio(false);
cin.tie(NULL);
int N, M, K;
cin >> N >> M >> K;
for (int i = 0; i < N; i++) {
long long d;
cin >> d;
dps.insert({ i + 1, d });
}
for (int i = 0; i < K; i++) {
long long hp, meso;
cin >> hp >> meso;
bossinfo.push_back({hp, meso});
}
for (int i = 0; i < N; i++) {
long long thisdps = dps[i + 1];
long long dp[14][901] = { 0, };
for (int j = 1; j <= K; j++) {
long long huntingTime = bossinfo[j - 1].first / thisdps;
long long value = bossinfo[j - 1].second;
if (bossinfo[j - 1].first % thisdps != 0) huntingTime++;
for (int k = 1; k <= 900; k++) {
if (k >= huntingTime)
dp[j][k] = max(dp[j - 1][k], dp[j - 1][k - huntingTime] + value);
else
dp[j][k] = dp[j - 1][k];
}
}
answer.push_back(dp[K][900]);
}
sort(answer.rbegin(), answer.rend());
long long ans = 0;
for (int i = 0; i < M; i++) {
ans += answer[i];
}
cout << ans << '\n';
}
'백준 문제 풀이' 카테고리의 다른 글
백준 7579번 앱 (C++) (0) | 2023.12.15 |
---|---|
백준 11729번 하노이 탑 이동 순서 (C++) (0) | 2023.12.15 |
백준 15681번 트리와 쿼리 (C++) (0) | 2023.12.13 |
백준 11438번 LCA 2 (C++) (0) | 2023.12.13 |
백준 16562번 친구비(C++) (1) | 2023.12.12 |