DP
Dynamic Programming
동적 프로그래밍
알고리즘 문제에서 많이 출제되며
아주 쉬운 난이도부터 아주 어려운 난이도까지 다양하게 산재
기초
점화식 도출
어떤 조건에서 완료할 것인지
어떤 예외 처리가 필요한지
에 대해 기본적으로 익히고 응용으로
----------
응용
실전 문제에서 이 문제가 DP로 해결되는지 모델링되는지 판단하는 것 -> 사실 DP로 풀 수 있는지 없는지 판단하는 것도 실력
(어떤 자료구조를 사용해서 이 정보로 다음 정보를 얻을 수 있고, 결과를 얻을 수 있는데.. 등)
DP이면서 여러 다른 알고리즘들을 사용해야 하는 문제 등
..
주저리주저리 썼지만
진짜 이건 다 개소리 맞는듯.
나중에 종만북에서 등장하는 알고리즘
개념?
현재 상태를 통해 다음 상태를 안다
-> 이전 정보를 통해 현재 정보를 안다.
간단한 예제를 들어 피보나치 수열을 구한다고 하자.
아래 소스 코드를 보면..
#include<bits/stdc++.h> int N;
long long a[91]={0,1};
int main(){ scanf("%d",&N); for(int i=2;i<N+1;i++){a[i]=a[i-1]+a[i-2];} printf("%lld",a[N]); }
현재 (i번 째) 피보나치 수열을 알고 싶을 때 이전 수열 값(i-1, i-2)번 째 값을 사용한다.
점화식은? a_i = a_(i-1)+ a_(i-2)
어떤 조건에서 완료? i==n
어떤 예외 처리? 딱히 없음..
이게 전부입니다.
쉽죠
아뇨 어렵습니다.
다른 문제를 볼까요?
n가지 종류의 동전이 있다. 각각의 동전이 나타내는 가치는 다르다. 이 동전들을 적당히 사용해서, 그 가치의 합이 k원이 되도록 하고 싶다. 그 경우의 수를 구하시오. (각각의 동전은 몇 개라도 사용할 수 있다.)
이문제는 백준 온라인저지의 "동전1" 이라는 문제입니다.
이제 생각해보자
아.. 문제 접근법에 대한 포스팅도 해야될거같다.
너무 막나간 느낌이랄까
일단. 그럼. 이 문제를 풀기 위해 모델링을 해보자.
힌트는 단 하나 DP로 풀린다.
각자 먼저 생각해보길
답은 여러 방법으로 나올 수 있겠지만
내가 푼 방법은 돈 액수 자체를 하나의 상태(인덱스)로 보고, 만들 수 있는 방법의 수를 value로 넣었다.
즉 a[idx]안에 담긴 value는 idx원을 만드는 방법의 갯수 이다.
예를 들어 보자.
1원 2원 5원 짜리 동전이 있고
10원을 만드는 방법의 수를 물어봤을 때
배열의 값들은 어떻게 될까?
a[0] = 0 --- 없음
a[1] = 1 --- (1*1 + 2*0 + 5*0)
a[2] = 2 --- (1*2 + 2*0 + 5*0) / (1*0 + 2*1 + 5*0)
a[3] = 2 --- (1*3 + 2*0 + 5*0) / (1*1 + 2*1 + 5*0)
a[4] = 3 --- (1*4 + 2*0 + 5*0) / (1*2 + 2*1 + 5*0) / (1*0 + 2*2 + 5*0)
a[5] = 4 --- (1*5 + 2*0 + 5*0) / (1*3 + 2*1 + 5*0) / (1*1 + 2*2 + 5*0) / (1*0 + 2*0 + 5*1)
생각해보자 무엇이 보이는가?
a[0] = 0
a[1] = (a[0] + 1원)
a[2] = (a[1] + 1원) / (a[0] + 2원)
a[3] = (a[2] + 1원) / (a[1] + 2원)
a[4] = (a[3] + 1원) / (a[2] + 2원)
a[5] = (a[4] + 1원) / (a[3] + 2원) / (a[0] + 5원)
점화식이 보이는가?
a[5] ----- 5원을 만들 수 있는 방법의 수는
a[4] + a[3] + a[0] 이다.
왜? 4원을 만들 수 있는 방법의 수(1원 더하면됨) + 3원을 만들 수 있는 방법의 수(2원 더하면됨) + 0원을 만들 수 있는 방법의 수(5원 더하면됨)
여기서 의문점은.. 만약 3원을 만들 수 있는 방법의 수에서 1원을 2번 더하면 안되냐?
-> 3원을 만들 수 있는 방법의 수에서 1원을 2번 더하는 행위는 4원을 만들 수 있는 방법의 수에서 1원을 더하는 것에 포함된다.
즉, 중복 포함되어 버린다.
이해가 안 간다면 계속 곱씹어서 생각하길 빈다.
진짜 쉬운 문제다.
이해했다면 위 문제 링크를 따라 문제를 풀어보도록 해라.
아래는 정답
#include<bits/stdc++.h> using namespace std; int n,k,i,j,c,dp[10001]={1,}; int main(){ scanf("%d%d",&n,&k); for(i=1;i<=n;++i){ scanf("%d",&c); for(int j=0;j<=k-c;++j) dp[j+c]+=dp[j]; } printf("%d",dp[k]); }
'job sound' 카테고리의 다른 글
[알고리즘] 문제 풀이 주제별 관련 우선순위 (0) | 2017.05.11 |
---|---|
[C++] BFS와 DFS (0) | 2017.05.11 |
[python] 크롤러를 만들어 크롤링을 해보자. (0) | 2017.05.11 |
[Windows] Windows 10 부팅(설치) 디스크를 만들어보자 (0) | 2017.04.17 |
[Ubuntu] Ubuntu 부팅(설치) 디스크를 만들어보자 (0) | 2017.04.10 |