문제 : 원주율 외우기 (난이도 : 下)
분석
조각의 길이가 3, 4, 5 중 하나이므로 다음과 같이 생각해보자.
1. 길이가 3인 조각 난도 + 3글자 뺀 나머지 수열에 대한 최적해
2. 길이가 4인 조각 난도 + 4글자 뺀 나머지 수열에 대한 최적해
3. 길이가 5인 조각 난도 + 5글자 뺀 나머지 수열에 대한 최적해
시작 위치가 주어졌을 때 최소 난도를 반환하는 함수를 memorize(begin),
주어진 구간([a, b])의 난도를 반환하는 함수를 classify(a, b)라 하자.
구현
const int INF = 987654321;
string input;
//input[a, b] 구간의 난도를 반환한다.
//난도를 판단하는 if문 눈에 익혀두자.
int classify(int a, int b)
{
//조각
string piece = input.substr(a, b - a + 1);
//난도 1
if (piece == string(piece.size(), piece[0])) return 1;
//등차수열; 공차 +-1 -> 난도 2, else -> 난도 5
bool progressive = true;
int d = piece[1] - piece[0];
for (int i = 0; i < piece.size() - 1; i++)
{
if (piece[i + 1] - piece[i] != d)
{
progressive = false;
}
}
if (progressive)
{
if (abs(d) == 1) return 2;
return 5;
}
//난도4
bool alter = true;
for (int i = 0; i < piece.size(); i++)
{
if (piece[i] != piece[i%2])
{
alter = false;
}
}
if (alter) return 4;
//else 난도 10
return 10;
}
int cache[10002];
int memorize(int begin)
{
//base case; 수열의 끝에 도달했을 경우
if (begin == input.size()) return 0;
//memoization
int& ret = cache[begin];
if (ret != -1) return ret;
ret = INF;
for (int L = 3; L <= 5; L++)
{
if (begin+L <= input.size())
{
ret = min(ret, memorize(begin + L) + classify(begin, L + begin - 1));
}
}
return ret;
}
int main()
{
int c;
cin >> c;
while (c--)
{
memset(cache, -1, sizeof(cache));
cin >> input;
cout << memorize(0) << '\n';
}
return 0;
}
'알고리즘 > 알고리즘 문제 해결 전략' 카테고리의 다른 글
동적 계획법 - 8. 타일링 방법의 수 세기 (0) | 2021.01.01 |
---|---|
동적 계획법 - 7. Quantization (0) | 2020.12.31 |
동적 계획법 - 5. 합친 LIS (0) | 2020.12.29 |
동적 계획법 - 4. 최대 증가 부분 수열 (0) | 2020.12.27 |
동적 계획법 - 3. 삼각형 위의 최대 경로 (0) | 2020.12.24 |