1. 다이나믹 프로그래밍이란 (Dynamic Programming )
가장 익숙한 다이나믹 프로그래밍의 예는 재귀함수를 배울때 피보나치 수열에서 배웠다.
int Fi(int num)
{
if(num == 1)
return 1;
else if( num ==2 )
return 1;
else
return Fi(num-1)+Fi(num-2);
}
위의 피보나치 수열 처럼 어떠한 문제는 작은 문제들의 합이 될수 있다는 개념이 다이나믹 프로그래밍의 기초이다.
위의 F 는 여러개의 작은 sub F 로 풀 수 있다.
피보나치 수열에서 한것처럼 위에서 부터 F 를 나눠서 플어나가는 방식을 Top-down 방식이라고 한다.
위와 같은 Top-down 방식은 함수를 계속해서 호출해야 되어서 나중에는 스택오버 플로우 문제를 야기할 수 있다.
그리고 위의 F(3) 의 경우 왼쪽에서 1번 계산하지만 오른쪽 줄기에서도 계산해야 한다 이미 F(3) 의 값을 계산했는데 한번더 하는것은 프로그램의 속도를 줄일 뿐이다.
이러한 부분을 보완하기 위해서 Bottom - up 방식이 존재한다.
Bottom - up
Bottom -up 방식이란 Top-dowm 방식과는 반대로 및에서부터 위로 올라가는 방식이다.
항상 F(n) 의 값을 갖는 배열을 정의한다음
F(1) 부터 차례대로 구하는 것이다. 결국 F(n) 까지 구하개되면 프로그램은 끝나고 시간 복잡도는 0(n) 이된다.
밑의 예제를 보면서 Bottom-up 에 대해서 이해해 보자
예제 1 )
https://www.acmicpc.net/problem/1463
1463번: 1로 만들기
첫째 줄에 1보다 크거나 같고, 106보다 작거나 같은 정수 N이 주어진다.
www.acmicpc.net
#include<iostream>
#include<cstring>
#include<algorithm>
using namespace std;
// dp botton up 방식
int main(void)
{
int Num ;
cin >> Num;
int* dp_array = (int*)malloc(sizeof(int)* (Num + 1));
memset(dp_array, 0, sizeof(int) * (Num + 1));
dp_array[1] = 0;
if (Num > 1)
{
for (int i = 2; i <= Num; i++)
{
dp_array[i] = dp_array[i - 1] + 1;
if (0 == (i % 2))
{
dp_array[i] = min(dp_array[i], dp_array[i / 2] + 1);
}
if (0 == (i % 3))
{
dp_array[i] = min(dp_array[i], dp_array[i / 3] + 1);
} // 모든 경우의 수를 비교하기 위해서 if 쓴다
}
}
cout << dp_array[Num];
return 0;
}
2 로 나뉘는 경우 , 3으로 나뉘는 경우 -1 하는경우 모든 경우의 수를 비교해야 한다.
예제 2 )
https://programmers.co.kr/learn/courses/30/lessons/43105
코딩테스트 연습 - 정수 삼각형
[[7], [3, 8], [8, 1, 0], [2, 7, 4, 4], [4, 5, 2, 6, 5]] 30
programmers.co.kr
#include<iostream>
#include <string>
#include <vector>
using namespace std;
int solution(vector<vector<int>> triangle) {
int answer = 0;
vector<vector<int>> triangle_copy;
if (0 == triangle.size()) { return triangle[0][0]; } // 삼각형의 높이가 1 이면 꼭대기 값 return
for(int i = (triangle.size()-2); i >=0; i--)
{
for (int j = 0; j < triangle[i].size(); j++)
{
triangle[i][j] = triangle[i][j] + max(triangle[i + 1][j], triangle[i + 1][j + 1]);
}
}
answer = triangle[0][0];
return answer;
}
int main()
{
vector<vector<int>> triangle = { vector<int>{7}, vector<int>{3, 8}, vector<int>{8, 1, 0}, vector<int>{2, 7, 4, 4},vector<int>{4, 5, 2, 6, 5}};
cout << solution(triangle);
return 0;
}
예제 3
등굣길
https://programmers.co.kr/learn/courses/30/lessons/42898#
코딩테스트 연습 - 등굣길
계속되는 폭우로 일부 지역이 물에 잠겼습니다. 물에 잠기지 않은 지역을 통해 학교를 가려고 합니다. 집에서 학교까지 가는 길은 m x n 크기의 격자모양으로 나타낼 수 있습니다. 아래 그림은 m =
programmers.co.kr
효용성에서 틀리는데 ;; 느리다누 ㅠㅠ
#include<iostream>
#include <string>
#include <vector>
using namespace std;
//void printMap(int** map, int m, int n)
//{
// for (size_t i = 0; i < n; i++)
// {
// for (size_t j = 0; j < m; j++)
// {
// cout << map[i][j];
// }
// cout << endl;
// }
//}
int solution(int m, int n, vector<vector<int>> puddles) {
int answer = 0;
int** map = new int*[n];
// 동적 할당
for (size_t i = 0; i < n; i++)
{
map[i] = new int[m];
}
// 데이타 초기화
for (size_t i = 0; i < n; i++)
{
for (size_t j = 0; j < m; j++)
{
map[i][j] = 0;
}
}
// puddles 인 곳은 -1 저장
for (size_t i = 0; i < puddles.size(); i++)
{
map[puddles[i][1] - 1][puddles[i][0] - 1] = -1;
}
// 외각 은 무조건 1
map[n - 1][m - 1] = 1;
//printMap(map, m ,n );
if (1 != m && 1 != n) // 1줄만 있는경우 제외
{
for (int i = n - 1; i > -1; i--)
{
for (int j = m - 1; j > -1; j--)
{
if (-1 == map[i][j])
{
continue;
}
if ((j + 1) <= ( m - 1))
{
if (-1 != map[i][j + 1])
{
map[i][j] = map[i][j] + map[i][j + 1];
}
}
if ((i + 1) <= (n - 1))
{
if (-1 != map[i + 1][j])
{
map[i][j] = map[i][j] + map[i + 1][j];
}
}
}
}
//printMap(map, m, n);
answer = map[0][0];
}
else
{
answer = 1;
}
// 동적 할당 해제
for (size_t i = 0; i < n; i++)
{
delete map[i];
}
delete[] map;
return answer;
}
int main()
{
vector<vector<int>> a = { {2, 2},{1,2},{3,2},{4,2} };
vector<vector<int>> b = { {2, 2}};
cout << solution(4, 3, a);
return 0;
}
'공부,일 > 코딩테스트' 카테고리의 다른 글
탐욕법 (0) | 2021.11.04 |
---|---|
전화번호 목록 (0) | 2021.10.24 |
tow sum (0) | 2021.10.24 |
코딩 테스트 사이트 모음 (0) | 2021.10.18 |
카카오톡 신입 공채 (0) | 2021.08.20 |
댓글