이번 프로그램은 개인적으로도 재미있을 것 같았습니다.
가장 중요한 알고리즘은 바로 동적 프로그래밍(Dynamic Programming)입니다. 실제 경로 문제 중 최적값 찾기에는 동적 프로그래밍 기법을 자주 사용하게 되는데, 이 프로그램 역시 마찬가지입니다.
해당 사이트 문제에서도 그런 점을 언급하기는 했지만,
동적 프로그래밍을 사용하지 않는다면, 경로의 수가 많은 경우에는 매우 많은 연산을 하게 됩니다. 이번 문제는 경로의 수가 16,384가지가 나옵니다. 왜냐하면 각 층의 숫자마다 경로가 2가지씩 나오니까요. 총 15층이므로, 총 경로의 수는 가 됩니다.
그러나 동적 프로그래밍을 이용하면, 실제 경로의 수 계산은 총 숫자의 갯수인 120가지밖에 안 됩니다. #67 문제에 100층짜리 문제가 나온다고 합니다. 100층의 경우에는 어마어마한 숫자가 되겠죠. 2의 99승이니, 어림잡아 계산해도 10의 30승 정도 됩니다. 그러나 동적 프로그래밍을 이용하면, 5,050 정도 계산량에 그칠겁니다. (물론 메모리는 그만큼 더 쓰겠죠.)
[실행결과]
실행결과는 경로를 표시한 것까지 했습니다. 사실 답만 딱 내어도 되겠지만요.
답은 예의상 지웠습니다. 물론 인터넷 검색을 하면, 답까지 나와있는 곳도 있겠죠?
프로그램을 작성할 때, 비재귀적 프로그램으로 작성할 수도 있겠지만, 저는 재귀적 프로그램으로 작성해보았습니다. #67 문제를 풀 때에는 재귀적 프로그램보다는 비재귀적 프로그램으로 짜보는 것이 좋다고 생각합니다. (재귀적 프로그램은 상당히 비싼 방법이며, 또한 스택이 가득차는 불상사가 생길 수도 있습니다.)
아래에 소스를 첨부합니다.
void printtriangle(int h[], int n); int getmax(int h[], int d[], int s, int c, int n); int f[1000]; int main() { char s[] = " 75 95 64 17 47 82 18 35 87 10 20 \ 04 82 47 65 19 01 23 75 03 34 88 02 77 73 07 63 \ 67 99 65 04 28 06 16 70 92 41 41 26 56 83 40 80 \ 70 33 41 48 72 33 47 32 37 16 94 29 53 71 44 65 \ 25 43 91 52 97 51 14 70 11 33 28 77 73 17 78 39 \ 68 17 57 91 71 52 38 17 14 91 43 58 50 27 29 48 \ 63 66 04 68 89 53 67 30 73 16 69 87 40 31 04 62 \ 98 27 23 09 70 98 73 93 38 53 60 04 23"; int h[1000]; int d[1000]; int n = 0; memset(d, 0, sizeof(d)); for( char *tok = strtok(s, " ") ; tok ; tok = strtok(0, " ") ) { h[n++] = atoi(tok); } printf("Ans = %d\n", getmax(h, d, 0, 1, n)); int c = 0; while( c < n ) { h[c] = -h[c]; c = f[c]; } printtriangle(h, n); } int getmax(int h[], int d[], int s, int c, int n) { if( s >= n ) return 0; if( d[s] ) return d[s]; int a = getmax(h, d, s+c, c+1, n); int b = getmax(h, d, s+c+1, c+1, n); if( a > b ) { f[s] = s+c; return d[s] = a+h[s]; } f[s] = s+c+1; return d[s] = b+h[s]; } void printtriangle(int h[], int n) { int u = 40; for( int i = 0 ; ; i++ ) { int s = i*(i+1)/2; if( n < s+i+1 ) break; printf("%*s", u-i*2, ""); for( int j = 0 ; j < i+1 ; j++ ) { if( h[s+j] < 0 ) printf("\033[1;34m%02d\033[0m ", -h[s+j]); else printf("%02d ", h[s+j]); } putchar('\n'); } }
'Programming > Project Euler' 카테고리의 다른 글
20. 프로젝트 오일러 #20 : 100!의 모든 자릿수 합 구하기 (0) | 2015.01.17 |
---|---|
19. 프로젝트 오일러 #19 : 20세기의 매달 1일이 일요일인 수 계산하기 (0) | 2015.01.17 |
17. 프로젝트 오일러 #17 : 영어 단어의 글자수 세기. (0) | 2015.01.14 |
16. 프로젝트 오일러 #16 : 2의 1000승의 모든 자릿수 합 구하기. (0) | 2015.01.13 |
프로젝트 오일러 #15 격자 경로의 수 구하기 (0) | 2014.12.31 |
댓글