DP (동적 계획법)
DP란 Dynamic Programming의 약자이며 최적화 문제를 해결하는 알고리즘 설계기법 중 하나이다.
- 입력 크기가 작은 부분 문제들을 모두 해결한 후에 그 해들을 이용하여 보다 큰 크기의 부분 문제를 해결한다
- 최종적으로 원래 주어진 입력의 문제를 해결한다
즉 점층적으로 문제를 해결해나가는 방식이다.
앞선 예제인 피보나치 수열을 DP 방식으로 해결해보자.
- 문제를 부분 문제로 분할한다
- F(N) = F(N-2) + F(N-1)
- F(N-1) = F(N-3) + F(N-2)
- ...
- F(3) = F(2) + F(1)
- 부분 문제로 나누는 일이 끝났으면 작은 부분부터 해를 구한다.
- F(2) = 1, F(1) = 1 이다
- 부분 문제의 해를 이용하여 전체의 해를 구한다.
- F(2)와 F(1)을 이용하여 전체의 해를 구한다.
보통 Memorization는 재귀적 구조에 사용하는 것보다 반복문에서 사용하는 것이 효율적이다. 재귀 함수에서는 스택 오버플로우가 발생할 수 있다.
DP구현 - 피보나치 수열 ( 재귀함수 )
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 | public class FibonacciNumberDP { private static Integer[] fArr; public static void main(String[] args) { fArr = new Integer[46]; fArr[0] = 0; fArr[1] = 1; fArr[2] = 1; int number = getFibonacciNumber(45); System.out.println(number); } public static int getFibonacciNumber(int index) { if(fArr[index] != null) { return fArr[index]; } fArr[index] = getFibonacciNumber(index-2) + getFibonacciNumber(index-1); return fArr[index]; } } | cs |
DP구현 - 피보나치 수열 (반복문)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 | public class FibonacciNumberDP2 { private static Integer[] fArr; public static void main(String[] args) { fArr = new Integer[46]; fArr[0] = 0; fArr[1] = 1; fArr[2] = 1; for(int i=3; i<46; i++) { fArr[i] = fArr[i-2] + fArr[i-1]; } int result = fArr[45]; System.out.println(result); } } | cs |
DFS(깊이우선탐색)
비선형구조인 그래프 구조를 검색하는 두 가지 방법 중 하나이다.
- 시작 정점의 한 방향으로 갈 수 있는 경로가 있는 곳까지 깊이 탐색한다
- 더 이상 갈 곳이 없게 되면, 가장 마지막에 만났던 갈림길 간선이 있는 정점으로 되돌아온다
- 다른 방향의 정점으로 탐색을 계속 반복하여 모든 정점을 방문, 순회한다
가장 마지막에 만났던 갈림길의 정점으로 되돌아가서 다시 깊이 우선탐색을 반복해야 하므로 후입선출 구조의 Stack을 사용하는게 적절하다.
DFS를 구현해보자
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 | import java.util.EmptyStackException; import java.util.Stack; public class DFS_깊이우선탐색 { public static boolean[] visitedArr = new boolean[7]; public static void main(String[] args) { // 탐색 정점 표시 a,b,c,d,e,f 방문표시 for(int i=0; i<visitedArr.length; i++) { visitedArr[i] = false; } // 그래프 연결 Data g = new Data("g", 6, null); Data f = new Data("f", 5, g); Data e = new Data("e", 4, f); Data d = new Data("d", 3, f); Data c = new Data("c", 2, e); Data b = new Data("b", 1, d, e); Data a = new Data("a", 0, b, c); // 정점 스택 Stack<Data> dataStack = new Stack<>(); try { // 순회 시작점 a Data start = a; do { start.visit(); // 방문하지않은 정점 찾기 Data unvisit = start.getNotVisit(); if(unvisit != null) { dataStack.push(start); } System.out.println("[정점]:"+start.getName()+"->"); while(unvisit != null) { System.out.println("\t[방문 정점]:"+unvisit.getName()); unvisit.visit(); // 방문하지 않은 정점찾기 if(unvisit.getNotVisit() != null) { dataStack.push(unvisit); unvisit = unvisit.getNotVisit(); } else { unvisit = null; } } start = dataStack.pop(); } while(start != null); } catch(EmptyStackException e1) { // 방문결과확인 for(int i=0; i<visitedArr.length; i++) { System.out.println(visitedArr[i]); } } } } class Data { private String name; private int index; private Data[] links; public Data(String name, int index, Data... data) { this.name = name; this.index = index; this.links = data; } public String getName() { return this.name; } public void visit() { DFS_깊이우선탐색.visitedArr[index] = true; } public boolean isVisit() { return DFS_깊이우선탐색.visitedArr[index]; } public Data getNotVisit() { Data unvisit = null; if(links == null) { return null; } for(int i=0; i<links.length; i++) { Data link = links[i]; if(!link.isVisit()) { unvisit = link; break; } } return unvisit; } } | cs |
'알고리즘 > SW Expert Academy' 카테고리의 다른 글
백트래킹 - NQueen (0) | 2019.05.15 |
---|---|
Stack(3) - 계산기(문자열 수식), 백트래킹 기법 (0) | 2019.04.04 |
Stack(1) - 스택과 memorization (0) | 2019.03.19 |
문자열 (String) (0) | 2019.02.16 |
Sort(정렬)에 대해서 - Selection Sort (0) | 2019.02.09 |