728x90
728x90
문제
오른쪽 그림과 같이 삼각형이 나선 모양으로 놓여져 있다. 첫 삼각형은 정삼각형으로 변의 길이는 1이다. 그 다음에는 다음과 같은 과정으로 정삼각형을 계속 추가한다. 나선에서 가장 긴 변의 길이를 k라 했을 때, 그 변에 길이가 k인 정삼각형을 추가한다.
파도반 수열 P(N)은 나선에 있는 정삼각형의 변의 길이이다. P(1)부터 P(10)까지 첫 10개 숫자는 1, 1, 1, 2, 2, 3, 4, 5, 7, 9이다.
N이 주어졌을 때, P(N)을 구하는 프로그램을 작성하시오.
입력
첫째 줄에 테스트 케이스의 개수 T가 주어진다. 각 테스트 케이스는 한 줄로 이루어져 있고, N이 주어진다. (1 ≤ N ≤ 100)
출력
각 테스트 케이스마다 P(N)을 출력한다.
예제 입력 1
2
6
12
예제 출력 1
3
16
출처
ICPC > Regionals > Asia Pacific > Korea > Asia Regional - Daejeon 2013 G번
알고리즘 분류
- 수학
- 다이나믹 프로그래밍
문제 출처
https://www.acmicpc.net/problem/9461
문제 해결 방법
점화식 구하기
- 문제에서 주어진 그림을 통해 도출되는 값을 분석하면 다음과 같다.
N | 출력값(P(N)) |
1 | 1 |
2 | 1 |
3 | 1 |
4 | 2 |
5 | 2 |
6 | P(5) + P(1) = 3 |
7 | P(6) + P(2) = 4 |
8 | P(7) + P(3) = 5 |
9 | P(8) + P(4) = 7 |
10 | P(9) + P(5) = 9 |
- $N ≥ 6$ 일 경우, 다음과 같이 점화식을 구할 수 있다.
$$P(N) = P(N - 1) + P(N - 5)$$
점화식을 토대로 구현하기
- $N \ge 6$ 부터 점화식이 성립하므로, DP 테이블에서 $1 \le N < 6$ 범위는 문제에서 주어진 수(@1@, @1@, @1@, @2@, @2@)로 채운다.
// P(N) = P(N - 1) + P(N - 5) (N >= 6)
ULL Calc(int n) {
dp[1] = dp[2] = dp[3] = 1;
dp[4] = dp[5] = 2;
for (int i = 6; i <= n; i++) {
dp[i] = dp[i - 1] + dp[i - 5];
}
return dp[n];
}
- @N = 100@ 일 경우, @888855064897@ 의 큰 수가 출력된다. 따라서 DP 테이블의 자료형을 @unsigned long long@ 으로 선언하하여 DP 테이블에 큰 수가 담길 수 있도록 하였다.
using ULL = unsigned long long;
vector<ULL> dp;
void Input() {
cin >> N;
dp.resize(N + 1);
}
정확하게 풀기
- 파도반 수열의 정확한 점화식은 $P(1) = P(2) = P(3) = 1, \quad P(N) = P(N - 1) + P(N - 2) \; (N \ge 4)$ 이다.
- 이 점화식을 토대로 코드를 작성하면 다음과 같다.
// P(1) = P(2) = P(3) = 1 (N < 4)
// P(N) = P(N - 2) + P(N - 3) (N >= 4)
ULL Calc(int n) {
dp[1] = dp[2] = dp[3] = 1;
for (int i = 4; i <= n; i++) {
dp[i] = dp[i - 2] + dp[i - 3];
}
return dp[n];
}
코드
#include <iostream>
#include <vector>
using namespace std;
using ULL = unsigned long long;
int T, N;
vector<ULL> dp;
void Input() {
cin >> N;
dp.resize(N + 1);
}
// P(N) = P(N - 1) + P(N - 5) (N >= 6)
ULL Calc(int n) {
dp[1] = dp[2] = dp[3] = 1;
dp[4] = dp[5] = 2;
for (int i = 6; i <= n; i++) {
dp[i] = dp[i - 1] + dp[i - 5];
}
return dp[n];
}
void Output() {
cout << Calc(N) << '\n';
dp.empty();
}
int main() {
ios_base::sync_with_stdio(false);
cin.tie(NULL);
cout.tie(NULL);
cin >> T;
for (int i = 0; i < T; i++) {
Input();
Output();
}
return 0;
}
채점 결과
참고
- [단계별로 풀어보기] > [동적 계획법 1]
- 실버III
파도반 수열(Padovan Sequence)
점화식($P(n)$)
- $n \le 2$ 의 경우 점화식은 다음과 같다.
$$P(0)=P(1)=P(2)=1$$
- $n > 3$ 의 경우 점화식은 다음과 같다.
$$P(n)=P(n-2)+P(n-3)$$
참고 사이트
728x90
728x90
'Problem Solving > BOJ' 카테고리의 다른 글
[BOJ-1932][C++] 정수 삼각형 (0) | 2022.12.08 |
---|---|
[BOJ-1149][C++] RGB거리 (0) | 2022.12.08 |
[BOJ-11652][C++] 카드 (0) | 2022.12.07 |
[BOJ-1912][C++] 연속합 (0) | 2022.12.07 |
[BOJ-1904][C++] 01타일 (0) | 2022.12.07 |
[BOJ-9184][C++] 신나는 함수 실행 (0) | 2022.12.04 |
[BOJ-24416][C++] 알고리즘 수업 - 피보나치 수 1 (0) | 2022.12.01 |
[BOJ-14889][C++] 스타트와 링크 (0) | 2022.12.01 |