BOJ 백준 1495 : 기타리스트
Updated:
시작하면서
이번 문제는 다이나믹 프로그래밍 문제이다.
문제 이해
해당 문제는 조건을 잘 이해해야한다.
- 곡의 개수 N의 최대값은 100이다.
- 볼륨 M의 최대값은 1000이다.
- 시작 볼륨은 M보다 작다.
만약 조건이 없다고 생각하고 모든 경우의 수를 다 해본다고 가정하면, 한 depth에서 P+V[i], P-V[i] 로 총 2번의 계산이 나오므로 depth의 최대값인 100번을 하게 되면 2^100 이라는 어마어마한 수치가 나오게 된다.
이때 조건을 보면 볼륨은 0보다 밑으로 내려갈 수 없고, 최대값인 1000이상으로는 올라갈 수 없으므로 범위가 상당히 좁다는 것을 알 수 있다. 그래서 매번의 계산마다 겹치는 부분이 많이 생길 것이므로 볼륨의 최대값인 M을 기준으로 계산했는지 여부를 판단하고, 이미 계산한 볼륨 숫자라면 건너뛰는 방식으로 한 depth에서 최대 계산을 1000번으로 줄일 수 있다.
이렇게 줄이면 최대의 계산 값은 100(N의 최대값) * 1000(볼륨의 최대값) = 약 100,000번으로 줄어든다.
해결
#include <iostream>
#include <vector>
#include <queue>
#include <math.h>
using namespace std;
int main()
{
// sync off
ios::sync_with_stdio(false);
cin.tie(0);
cout.tie(0);
// sync off
vector<bool> isUsed;
vector<int> volumes;
queue<int> q;
int preQcount = 0;
int N, S, M;
cin >> N >> S >> M;
volumes.resize(N);
for (int i = 0; i < N; i++)
{
cin >> volumes[i];
}
// 계산했는지 여부를 판단하는 벡터
isUsed.resize(M + 1);
// 시작 볼륨을 넣는다.
q.push(S);
preQcount = q.size();
for (int i = 0; i < N; i++)
{
// 이전 뎁스에서 넣은만큼만 계산한다.
while (preQcount > 0)
{
int value = q.front(); q.pop();
int calculatedValue = 0;
preQcount--;
// 볼륨을 높이는 경우
calculatedValue = value + volumes[i];
if (calculatedValue <= M && isUsed[calculatedValue] == false)
{
isUsed[calculatedValue] = true;
q.push(calculatedValue);
}
// 볼륨을 낮추는 경우
calculatedValue = value - volumes[i];
if (calculatedValue >= 0 && isUsed[calculatedValue] == false)
{
isUsed[calculatedValue] = true;
q.push(calculatedValue);
}
}
// 이번 뎁스에서의 큐 사이즈를 다음 뎁스에서 계산하기 위해 저장한다.
preQcount = q.size();
// 계산했는지 여부를 판단하는 벡터를 초기화한다.
isUsed.assign(isUsed.size(), false);
}
int result = -1;
// 마지막 뎁스까지 계산했을때 가장 큰 값을 찾는다.
while (!q.empty())
{
int value = q.front(); q.pop();
result = max(result, value);
}
cout << result;
return 0;
}
마치며
계산한 부분을 기록해서 반복 계산을 하지 않게 만드는 것도, 다이나믹 프로그래밍의 일부 개념으로 들어갈 수 있는 사실을 알았다.
Leave a comment