- Dynamic Programming
- Similar / Different to Divide and Conquer
- Step 1, Step 2
- 3.1 : The Binomial Coefficient
- Using Divide and Conquer
- Using Dynamic Programming
- Time Complexity
- 3.2 : Floyd's Algorithm for Shortest Path
- Shortest Paths Problem
- Simple Algorithm
- Floyd's Algorithm
- 3.3 Dynamic Programming and Optimization Problem
- 3.4 Optimal Binary Search Trees
- 3.6 Traveling SalesPerson Problem
Dynamic Programming
(1) Similar to “Divide and Conquer”
- an instance of a problem is divided into one or more smaller instances.
(2) Different from “Divide and Conquer”
- smaller instances are solved first, and then they are retrieved later when needed
먼저 구한 뒤, 필요시 꺼내쓴다.
Dynamic Programming is Bottom-Up
- Divide and Conquer is Top Down.
DP Top Down 방식 : memoization
Step 1: (중요)
Establish a recursive property that gives the solution to an instance of the problem.
Step 2 :
Solve an instance of the problem in a bottom-up fashion by solving smaller instances first.
3.1 The Binomial Coefficient
Binomial Coefficient
0<k<n : 1~n개 중 k개를 고를 때, n을 포함/불포함의 합으로 나타낸다
k=0 or k=n : 예외처리
Binomial Coefficient using Divide and Conquer
(1) code
Inputs:
n, k – nonnegative integers (k ≤ n)
Output: C(n,k)
public static int bin(int n, int k)
{
if (k==0 || k==n)
return 1 ;
else
return bin(n-1,k-1) + bin(n-1,k) ;
}
-> 시간 복잡도 (중복계산으로 오래걸림)
2C(n,k) - 1 개의 노드 계산이 필요하다.
T(n,k) = T(n-1, k-1) + T(n-1, k) + 1
Binomial Coefficient using Dynamic Programming
(1) 개념 설명
Suppose that we use 2- dim. array B to store all the values of C(i,j) ( 0 ≤ i ≤ n, 0 ≤ j ≤ k )
B[i][j]= { B[i-1][j-1]+B[i-1][j] (0<j<i),
1 (j=0 or i=j) }
이차원 배열을 이용해 위에서 아래로, 작은 값부터 체워넣어서 ? 값을 구한다.
(2) code
Inputs:
n, k – nonnegative integers (k ≤ n)
Output: C(n,k)
public static int bin2(int n, int k)
{
index i,j;
int [ ][ ] B = new int [0..n][0..k] ;
for (i=0; i<=n ; i++)
for (j=0; j <= min(i,k) ; j++)
if (j==0 || j==i)
B[i][j]=1;
else
B[i][j]=B[i-1][j-1]+B[i-1][j] ;
return B[n][k] ;
}
min( i, k)
3.2 Floyd’s Algorithm for Shortest Paths
The Shortest Paths Problem
1. simple source : 출발점 고정 ex) 다이스트라, 그리디
2. all path : 모든 순서쌍, 출발도착 고정 X ex) Floyd
Floyd’s Algorithm
(1) 개념설명
We use an n x n weight table W for a graph with n nodes
행 : start 노드 , 열 : end 노드 로 edge가 없는 경우 무한대로 표시하고 자기자신은 0으로 표현한다.
Given a pair of vertices (vi , vj ), 1≤ i, j ≤n,
i에서 j까지의 최단경로의 길이이다.
중간노드는 오직, 1에서 k까지의 노드를 이용한다. (1<=k<=n)
= W[i][j]
example : 위의 노드들 그림에서,
이므로, = min(length[v2 , v5 ], length[v2, v1, v5]) = min(∞ ,14) = 14
case 1 : 1~k의 중간노드에서 k를 지나지 않는 경우
case 2 : 1~k의 중간노드에서 k를 지나는 경우
Combine (case1 + case2)
(2) code
void floyd(int n, const number W[ ][ ],number D[ ][ ])
{
index i,j,k ;
D = W ;
for (k=1; k<= n ;k++)
for (i=1; i <= n ; i++)
for (j=1; j <= n ; j++)
D[i][j]=min(D[i][j],D[i][k]+D[k][j]);
T(n) = n * n * n
D[i][j]=min(D[i][j],D[i][k]+D[k][j]);
void floydPath(int n, const number W[ ][ ],number D[ ][ ], number P[][])
{
index i,j,k ;
for (i=1; i <= n ; i++)
for (j=1; j <= n ; j++)
P[i][j]=0 ;
D = W ;
for (k=1; k<= n ;k++)
for (i=1; i <= n ; i++)
for (j=1; j <= n ; j++)
if (D[i][k]+D[k][j] < D[i][j]) {
D[i][j] = D[i][k]+D[k][j] ;
P[i][j] = k ;
}
}
P[][]에 중간 경로를 저장해준다.
void path(index q, r)
{
if (P[q][r] != 0){
path(q, P[q][r]) ;
cout << “ v” << P[q][r] ;
path(P[q][r] , r) ;
}
}
최단 경로의 루트를 p를 통해 출력하기
3.3 Dynamic Programming and Optimization Problem
Principle of Optimality
항상 모든 subinstance들이 optimal solution에 포함되어야 한다.
Example: Shortest Path Problem
Counter Example: Longest Simple Path Problem
3.4 Optimal Binary Search Trees
Binary Search Tree
왼쪽 노드 <= root 노드 <= 오른쪽 노드 가 성립하는 트리이다.
void search(node_pointer tree, keytype keyin, node_pointer& p)
{
bool found = false;
p = tree ;
while ( ! found )
if (p->key == keyin)
found = true ;
else if (keyin < p->key)
p = p->left ;
else
p = p->right ;
}
BST에서, 찾고자 하는 keyin을 찾을 때의 알고리즘
/
BST 알고리즘에서 key1 <= key2 <= ... keyn의 조건이 있다.
Pi는 , key i가 찾는keyin일때의 확률을 뜻한다.
이때 우리는
Ci가 key를 찾을 때의 내려가는 depth라고 할 때,
확률과 depth의 최소값의 합을 구하려고 한다.
example : three keys Key1≤Key2 ≤ Key3, P1= 0.7, P2 =0.2 , Pn =0.1
조건(Key1≤Key2 ≤ Key3)에 맞는 BST는 다섯가지가 있는데
찾고자 하는 이 값의 최소값은 첫번째 BST가 된다.
이것이 optimal BST이다.
Dynamic Programming Approach
(1) DP로 풀 수 있는지 판단하기
(2) 배열 생성 및 배열의 의미부여하기
(3) boundary condition
(1) Suppose that keys Keyi through Keyj are arranged in a tree that minimizes
(2) 배열 생성.
and that A[i][j] is such a minimum value. (Note: A[i][i] = pi )
루트에 있는 key k 의 optimal binary search tree 를 생각해보자. 3.3 DP조건에 따라 왼쪽, 오른쪽 subtree는 must be optimal 이다.
왼쪽 subtree는 A[1][k-1], 오른쪽 subtree A[k+1][n]일 때,
왼쪽 subtree + 왼쪽 subtree들어가는 확률 값 + key k의 확률 + 오른쪽 subtree + 오른쪽 subtree들어가는 확률 값
(왼쪽 subtree들어가는 확률 값+key k의 확률 + 오른쪽 subtree들어가는 확률 값 ) 하나로 묶었다.
1<=k<=n은 위의 식이 root가 k인 경우의 식이니까, k의 범위대로 나타냄.
(3) boundary condition
i<=k<=j의 범위에서 k=i,j인 경우에서 조건을 넣어줘야 한다.
(4) code
우리가 구해야 하는 값은 A[1][n]이다. 즉 1에서 n까지 가는 최솟값.
이때 대각선을 이용해 빠르게 찾는다.
void optSearchTree(int n, const float p[], float& minavg, index R[][])
{
index i,j,k, diagonal; float A[1..n+1][0..n] ;
for (i=1; i<= n ; i++) {
A[i][i-1] = 0 ; A[i][i] = p[i] ;
R[i][i] = i ; R[i][i-1] = 0 ;
}
A[n+1][n] = 0 ; R[n+1][n] = 0 ;
for (diagonal=1;diagonal <= n-1;diagonal++)
for (i=1; i<= n-diagonal ; i++) {
j = i + diagonal ;
A[i][j]=min(A[i][k-1]+A[k+1][j])+∑m=ij pm;
R[i][j]=a value of k giving the minimum
}
minavg = A[1][n] ;
(1) boundary condition 작성
(2) for문
i : 행 번호, j : 열 번호
3.6 Traveling SalesPerson Problem
Traveling SalesPerson Problem
Given n nodes in a graph,
find the shortest route starting from a node and ending at itself
while visiting each of other nodes once.
모든 노드를 한번씩 방문하고 자기 자신으로 돌아오기까지의 최단경로
Dynamic Programming Approach
(1) V1에서 출발한다고 했을 때, 아래 그림들 중 하나가 답일 것이다.
(2) 배열 생성
Let V = {v1, v2, … , vn}, the set of all vertices
A = a subset of V ex) {v1,v2, v3}
D[vi ][A] = the length of shortest path from vi to v1 passing through each vertex in A exactly once
(vi에서 A의 노드를 지난 뒤 v1으로 돌아오는 경로들 중 , 최단경로 )
(3) boundary condition
시작노드를 v1이라고 하고 그다음 지나는 노드를 j라고 할 때,
경로의 값 = v1-vj의 weight 값 + D[vj][ 지나온 v1,vj를 제외한 노드 ]
example)
size = A가 갖고있는 노드개수
(4) code
void travel(int n, const number W[][],index p[][], number& minLength)
{
index i,j,k ; number D[1..n][subset of V –{v1}] ;
for (i=2;i<=n;i++)
D[i][∅] = W[i][1];
for (k=1; k<= n-2; k++)
for (all subsets A⊆V –{v1} containing k nodes)
for (i such that i≠1 and vi is not in A) do {
D[i][A] = min (W[i][j]+D[j][A-{vj}]);//vj∈ A
P[i][A] = value of j giving the minimum
}
D[1][V-{v1}]=min(W[1][j]+D[j][V-{v1 ,vj}]);//2≤j≤n
P[1][V-{v1}]=value of j that gave the minimum;
minLength = D[1][V-{v1}] ;
}
3중 for문에서
for (k=1; k<= n-2; k++)
for (all subsets A⊆V –{v1} containing k nodes)
D[ ][ ] : 두번째 괄호 조건들.
K 는 A의 size이다.
k 값에 따라서 k노드들을 포함하는
for (i such that i≠1 and vi is not in A) do {
D[ ][ ] : 첫번째 괄호 조건.
'programming language > Algorithm' 카테고리의 다른 글
[Dynamic Programming 예제] 백준 2957 BST (0) | 2021.08.14 |
---|---|
[Dynamic Programming 예제] 백준 11404 플로이드 (0) | 2021.08.14 |
[Divide and Conquer 예제] 백준 2751 수 정렬하기2 (0) | 2021.08.10 |
[Divide and Conquer 예제] 백준 1780 종이의 개수 (0) | 2021.08.10 |
[Divide and Conquer 예제] 프로그래머스 Level3 이분탐색 입국심사 (0) | 2021.08.06 |