다이나믹 문제 풀이 전략
https://www.acmicpc.net/problem/1463
1로 만들기
D[n] = min(D[n/3], D[n/2], D[n-1]) + 1 // 점화식
top-down 방식
#include <iostream>
#include <cstring>
using namespace std;
int d[1000001];
int go(int n) {
if (n == 1) {
return 0;
}
if (d[n] > 0) {
return d[n];
}
d[n] = go(n - 1) + 1;
if (n % 2 == 0) {
int temp = go(n / 2) + 1;
if (temp < d[n]) d[n] = temp;
}
if (n % 3 == 0) {
int temp = go(n / 3) + 1;
if (temp < d[n]) d[n] = temp;
}
return d[n];
}
int main() {
int n;
cin >> n;
memset(d, 0, sizeof(d));
cout << go(n) << '\n';
return 0;
}
bottom-up 방식
#include <iostream>
#include <cstring>
using namespace std;
int d[1000001];
int main() {
int n;
cin >> n;
memset(d, 0, sizeof(d));
d[1] = 0;
for (int i = 2; i <= n; i++) {
d[i] = d[i - 1] + 1;
if (i % 2 == 0 && d[i /2] +1 < d[i]) {
d[i] = d[i / 2] + 1;
}
if (i % 3 == 0 && d[i / 3] + 1 < d[i]) {
d[i] = d[i / 3] + 1;
}
}
cout << d[n] << '\n';
return 0;
}
https://www.acmicpc.net/problem/11726
2xn 타일링
n-2에 가로 두 개를 더하는 것과 n-1에 세로 한개를 더하는 것으로 풀이가 된다.
n-2에 세로 두개를 더하는 경우는 이미 n-1에 한개를 더하는 것으로 포함이 된다.
D[n] = D[n-1] + D[n-2]
bottom-up
#include <iostream>
#include <cstring>
using namespace std;
int d[1001];
int main() {
int n;
cin >> n;
memset(d, 0, sizeof(d));
d[1] = 1; d[2] = 2;
for (int i = 3; i <= n; i++) {
d[i] = d[i - 2] + d[i - 1];
d[i] %= 10007;
}
cout << d[n] << '\n';
return 0;
}
top-down
#include <cstdio>
int d[1001];
int go(int n) {
if (n == 1 || n == 2) {
return n;
}
if (d[n] > 0) {
return d[n];
}
else {
d[n] = go(n - 1) + go(n - 2);
return d[n] % 10007;
}
}
int main() {
int n;
scanf("%d", &n);
int ans = go(n);
printf("%d\n", ans);
return 0;
}
https://www.acmicpc.net/problem/11727
2xn 타일링 2
이전 문제에서 + D[n-2]가 추가 되었다. 이는 2x2 사각형을 하나 추가한 것과 같다.
D[n] = D[n-2] * 2 + D[n-1]
#include <iostream>
#include <cstring>
using namespace std;
int d[1001];
int main() {
int n;
cin >> n;
memset(d, 0, sizeof(d));
d[1] = 1; d[2] = 3;
for (int i = 3; i <= n; i++) {
d[i] = d[i - 2] * 2 + d[i - 1];
d[i] %= 10007;
}
cout << d[n] << '\n';
return 0;
}
https://www.acmicpc.net/problem/9095
1, 2, 3 더하기
D[n] = D[n-3] + D[n-2] + D[n-1]
n-3에 3을 더하는 경우, n-2에 2를 더하는 경우, n-1에 1을 더하는 경우가 있다.
#include <iostream>
#include <cstring>
using namespace std;
int d[12];
int main() {
int t;
cin >> t;
memset(d, 0, sizeof(d));
while (t--) {
int n;
cin >> n;
d[1] = 1; d[2] = 2; d[3] = 4;
for (int i = 4; i <= n; i++) {
d[i] = d[i - 3] + d[i - 2] + d[i - 1];
}
cout << d[n] << '\n';
}
return 0;
}
https://www.acmicpc.net/problem/15988
1, 2, 3 더하기 3
#include <iostream>
#include <cstring>
using namespace std;
long long d[1000001];
int main() {
int t;
cin >> t;
memset(d, 0, sizeof(d));
while (t--) {
int n;
cin >> n;
d[1] = 1; d[2] = 2; d[3] = 4;
for (int i = 4; i <= n; i++) {
d[i] = d[i - 3] + d[i - 2] + d[i - 1];
d[i] %= 1000000009;
}
cout << d[n] << '\n';
}
return 0;
}
https://www.acmicpc.net/problem/11052
카드 구매하기
초기화 할 때 i = 1 부터임에 유의해
i - j + j 를 해야 다시 i가 된다.
#include <iostream>
using namespace std;
int d[1001];
int p[1001];
int main() {
int n;
cin >> n;
for (int i = 1; i <= n; i++) {
cin >> p[i];
}
d[1] = p[1];
for (int i = 2; i <= n; i++) {
d[i] = p[i];
for (int j = 1; j <= i - 1; j++) {
if (d[i] < d[i - j] + p[j]) {
d[i] = d[i - j] + p[j];
}
}
}
cout << d[n] << '\n';
return 0;
}
https://www.acmicpc.net/problem/16194
카드 구매하기 2
이전 문제에서 부등호만 바꿔주면 된다.
https://www.acmicpc.net/problem/15990
1, 2, 3 더하기 5
컴퓨터는 이전에 1을 더했는지 2를 더했는지 몰라, 직접 기억 시켜줘야해
#include <iostream>
using namespace std;
long long d[100001][4];
#define mod 1000000009
int main() {
int t;
cin >> t;
while (t--) {
int n;
cin >> n;
d[1][1] = 1; d[1][2] = 0; d[1][3] = 0; d[1][0] = 1;
d[2][1] = 0; d[2][2] = 1; d[2][3] = 0; d[2][0] = 1;
d[3][1] = 1; d[3][2] = 1; d[3][3] = 1; d[3][0] = 3;
for (int i = 4; i <= n; i++) {
d[i][1] = (d[i - 1][2] + d[i - 1][3]) % mod;
d[i][2] = (d[i - 2][1] + d[i - 2][3]) % mod;
d[i][3] = (d[i - 3][1] + d[i - 3][2]) % mod;
d[i][0] = d[i][1] + d[i][2] + d[i][3];
d[i][0] %= mod;
}
cout << d[n][0] << '\n';
}
return 0;
}
위의 코드를 개선, 테스트 케이스에 대해 각각 다시 구할 필요가 없다.
#include <iostream>
using namespace std;
long long d[100001][4];
#define mod 1000000009
int main() {
int t;
cin >> t;
d[1][1] = 1; d[1][2] = 0; d[1][3] = 0; d[1][0] = 1;
d[2][1] = 0; d[2][2] = 1; d[2][3] = 0; d[2][0] = 1;
d[3][1] = 1; d[3][2] = 1; d[3][3] = 1; d[3][0] = 3;
for (int i = 4; i <= 100000; i++) {
d[i][1] = (d[i - 1][2] + d[i - 1][3]) % mod;
d[i][2] = (d[i - 2][1] + d[i - 2][3]) % mod;
d[i][3] = (d[i - 3][1] + d[i - 3][2]) % mod;
d[i][0] = d[i][1] + d[i][2] + d[i][3];
d[i][0] %= mod;
}
while (t--) {
int n;
cin >> n;
cout << d[n][0] << '\n';
}
return 0;
}
https://www.acmicpc.net/problem/10844
쉬운 계단 수
#include <iostream>
using namespace std;
#define mod 1000000000
long long d[101][10];
int main() {
int n;
cin >> n;
d[1][0] = 0;
for (int i = 1; i < 10; i++) {
d[1][i] = 1;
}
for (int i = 2; i <= n; i++) {
d[i][0] = d[i - 1][1];
for (int j = 1; j <= 8; j++) {
d[i][j] = (d[i - 1][j - 1] + d[i - 1][j + 1]) % mod;
}
d[i][9] = d[i - 1][8];
}
long long ans = 0;
for (int i = 0; i <= 9; i++) {
ans += d[n][i];
ans %= mod;
}
cout << ans << '\n';
return 0;
}
https://www.acmicpc.net/problem/11057
오르막 수
#include <iostream>
using namespace std;
long long d[1001][10];
#define mod 10007
int main() {
int n;
cin >> n;
for (int i = 0; i < 10; i++) {
d[1][i] = 1;
}
for (int i = 2; i <= n; i++) {
for (int j = 0; j <= 9; j++) {
for (int k = j; k >= 0; k--) {
d[i][j] += d[i - 1][k];
d[i][j] %= mod;
}
}
}
long long ans = 0;
for (int i = 0; i < 10; i++) {
ans += d[n][i];
ans %= mod;
}
cout << ans << '\n';
return 0;
}
https://www.acmicpc.net/problem/2193
이친수
#include <iostream>
using namespace std;
long long d[91][2];
int main() {
int n;
cin >> n;
d[1][0] = 0; d[1][1] = 1;
for (int i = 2; i <= n; i++) {
d[i][0] = d[i - 1][0] + d[i - 1][1];
d[i][1] = d[i - 1][0];
}
cout << d[n][0] + d[n][1] << '\n';
return 0;
}