본문 바로가기
반응형

동적 계획법23

[C/C++] 백준 #1937 욕심쟁이 판다(동적 계획법) 격자로 나누어진 공간에서 판다가 대나무를 먹는데, 옮긴곳이 이전보다 대나무가 더 많은 곳이어야 옮겨갈 수 있습니다. 판다는 이동을 할 때, 상하좌우중 하나를 선택해서 한칸만 옮겨갈 수 있습니다. 이 판다가 최대한 많은 대나무숲에서 식사를 할 수 있도록 하고자 할 때, 최대 이동횟수를 구하는 문제입니다. 조금 어려워보이지만, 전 일단 탐욕 방법을 사용했습니다. 판다가 처음 위치한 곳의 대나무숲이 적은 곳이어야 한다는 것이죠. 그래서 최대로 많은 곳까지 가는 대나무숲을 고르는 것이죠. \(V(s)\)의 값이 현재까지 이동한 횟수를 저장한다고 한다면, \[ V(s) = max_{s \rightarrow s'}(V(s'))+1 형태로 작성할 수 있습니다. 이것을 동적 계획법으로 풀기 위해서는 가장 적은 값부터 .. 2022. 11. 17.
[C/C++] 백준 #1932 정수 삼각형(동적 계획법) 이번 문제는 삼각형 형태로 이루어진 숫자 피라미드에서 위의 꼭지점에서 바닥까지 이동을 할 때, 숫자들의 합이 최대가 되는 것을 고르는 것입니다. 아랫단에서는 선택할 수 있는 위의 숫자들이 최대 두가지가 됩니다. 이 중 최대값과 더하면 어느 곳이든 꼭지점에서부터 해당 지점까지 오는 경로의 합 중 최대값이 됩니다. 이를 이용해서 프로그램을 작성하면 됩니다. 단, 해당 층에서 맨 왼쪽 원소와 맨 오른쪽 원소는 선택할 수 있는 윗단의 숫자가 하이므로 미리 처리를 하든지, 예외 처리를 하시면 됩니다. 제 경우에는 경계처리를 간단하게 하기 위해서 일단 모든 값을 0으로 초기화해서 경계처리를 했습니다. 이렇게 경계처리를 하면 조건 검사를 덜하거나 예외처리를 하지 않아도 된다는 장점이 있습니다. 위에서부터 내려오는 방.. 2022. 11. 14.
[C/C++] 백준 #1915 가장 큰 정사각형(동적 계획법) 이번 문제는 숫자가 써져있는 배열에서 1로만 채워진 가장 큰 정사각형을 찾으라는 문제입니다. 기본적인 알고리즘은 현재 셀을 포함한 가장 큰 정사각형을 찾는 것입니다. 현재 셀이 0이면 가장 큰 정사각형은 0입니다. 현재 셀이 1인 경우에만 가능하죠. A B C D 위의 그림에서 D에서 가장 큰 정사각형을 찾기 위해서는 D의 값이 0이면 0의 값이 됩니다. D의 값이 1일때만, ABCD 구역에서 D를 포함한 가장 큰 정사각형의 넓이를 구하는 것이죠. 첫번째는 A에서 가장 큰 정사각형입니다. 이 경우에는 D와 대각선으로 이웃한 셀은 1로 설정이 되어 있지않다면 0의 값을 가집니다. 다음으로는 AB에서 가장 큰 정사각형입니다. D의 위의 셀값은 1이 아니라면 0이겠죠. 다음으로는 AC에서 가장 큰 정사각형입니.. 2022. 11. 3.
[C/C++] 백준 #1904 01타일(피보나치 수열) 이번 문제는 복잡하게 썼지만, 결국 피보나치 수열을 구하는 문제입니다. 길이가 N인 01 타일의 이진수를 얻기 위해서는 길이가 N-1인 01 타일의 이진수에 1이 쓰인 타일을 붙이거나 길이가 N-2인 01 타일의 이진수에 00이 쓰인 타일을 붙여야 합니다. 이것을 식으로 표현하면, \[ d_{0} = 1 \] \[ d_{1} = 1 \] \[ d_{n} = d_{n-1} + d_{n-2} \] 점화식을 보면, 피보나치 수열임을 알 수 있습니다. 단지 시작점이 다른 피보나치 수열이죠. 피보나치 수열을 계산하는 방법은 단순하게 반복문을 돌리는 것이 편합니다. 재귀함수는 아주 시간이 많이 걸리고, 배열을 잡아서 하는 방법도 있지만, 전 그냥 편의상 두개의 변수만을 잡아서 사용했습니다. 제가 작성한 소스입니다... 2022. 11. 1.
[C/C++] 백준 #1890 점프(동적 계획법) 이번 문제는 동적 계획법을 이용해서 풀었습니다. 사실 동적 계획법이 아니라 너비 우선 탐색(BFS)를 사용해도 같은 결과를 얻을 수 있습니다. 그렇지만 단순 반복문을 사용할 수 있는 동적 계획법에 비해서 효율이 떨어지게 되겠죠. 동적 계획법 알고리즘은 간단합니다. \(d_{i, j} \)를 시작점에서 \((i, j)\)로 가는 경로의 개수라고 한다면, 1. NxN 공간을 0으로 초기화합니다. \( d_{i, j} = 0 \) 2. 시작점을 1로 놓습니다. 즉, 시작점에서 시작점으로 가는 경로는 한가지입니다. \(d_{0, 0} = 1\) 3. 시작점에서부터 오른쪽 방향 우선으로, 아래로 이동하면서 갈 수 있는 모든 곳 \(d_{i+a_{i, j}, j}\) 값과 \(d_{i, j+a_{i, j}}\) 값.. 2022. 11. 1.
[C/C++] 백준 #1699 제곱수의 합(동적 계획법) 어떤 수를 제곱수의 합으로 표현할 수 있습니다. 모든 자연수의 1을 해당 수만큼 더하면 되기 때문에 모든 자연수는 가능하다고 할 수 있습니다. 예를 들어서 10과 같은 수는 1을 10번 더해도 되겠지만, 9와 1을 더해도 되고, 4+4+1+1 형태도 가능합니다. 동적계획법을 단순하게 한다면, 다음과 같이 할 수가 있습니다. n을 만들 수 있는 제곱항의 수를 \(d_n\)이라고 한다면, \[ d_0 = 0 \] \[ d_n = min( d_{n-1}+d_1, d_{n-2}+d_2, ..., d_{n/2} + d_{(n+1)/2} ) \] 그런데 이렇게 하게 되면, \(d_n\)을 구하는 알고리즘 효율이 \(O( n ) \) 형태가 되게 되고 전체적으로는 \(O(n^2)\)이 됩니다. 그것을 줄이기 위해서 .. 2022. 9. 30.
728x90