170 likes | 359 Views
Dynamic Programming. Andrew Lim Zhu Wenbin. When to Use DP. Usually used to solve Optimization problems Usually the problem can be formulated as recursion The solution of a problem is made up the solutions of its sub-problems and sub-problems overlaps. E.g. Fibonacci Number.
E N D
Dynamic Programming Andrew Lim Zhu Wenbin
When to Use DP • Usually used to solve Optimization problems • Usually the problem can be formulated as recursion • The solution of a problem is made up the solutions of its sub-problems and sub-problems overlaps
E.g. Fibonacci Number • The problem (Background) • Every mature pair of rabbit give birth to a pair of rabbits in every month • Newly born rabbits become mature after one month • There is one pair of rabbit at beginning of a year, how many pairs are there after one year? • Formulation: • f(n) = f(n-1) + f(n-2); • f(1) = 1, f(2) = 2
FN Naïve Solution int f (int n) { int r; if (n<=2) r = n; else r = f(n-1) + f(n-2); return r; } f(6) | ------------------------- | | f(5) f(4) | | ---------------- ------------ | | | | f(4) f(3) f(3) f(2) | | | ------------ ------- ------- | | | | | | f(3) f(2) f(2) f(1) f(2) f(1) | -------- | | f(2) f(1)
FN: Memoization • Memorize whatever calculated, calculate only once /* Memoization Method. Assume n is at most 100 * long mem[101]; * memset(mem, 0, sizeof(mem)); */ int f (int n) { int r; if (mem[n] > 0) return mem[n]; if (n <= 2) r = n; else r = f(n-1) + f(n-2); mem[n] = r; return r; }
Turn Recursion into Memoization Initialize memory in main function int f () { if already calculated return the result calculate the result using recursion save the result in memory return the result }
FN: Fill-in-the-table method • Bottom up approach • Figure out the order in which the memory is filled in manually, fill in the table using loop long mem[101]; int f (int n) { int i; mem[1] = 1; mem[2] = 2; for (i = 3; i <= n; i++) mem[i] = mem[i-1] + mem[i-2]; return mem[n]; }
FN: Save Memory • Only previous two results are needed in every step, so just keep these two result int f (int n) { int pre_2, pre_1, cur, i; if (n <= 2) return n; pre_2 = 1; pre_1 = 2; for (i = 3; i <= n; i++) { cur = p_1 + p_2; p_1 = cur; p_2 = p_1; } return cur; }
E.g. Longest Common Subsequence • A subsequence is a sequence resulting from deleting a few items in original sequence: • “bdfk” is a subsequence of “abcdefghijklmn” • Given two strings find the longest common subsequence: • “adf” is common subsequence of “abdfg” and “adgfkg” • “adfg” is another
LCS: Formulation • A = a1a2a3…am B = b1b2b3…bn • Ai = a1a2a3…ai Bj = b1b2b3…bj • f (i, j) is the length of longest common subsequence of Ai and Bj • f (i, j) = 1 + f (i-1, j-1) if ai = bj • f (i, j) = max (f(i-1,j), f(i, j-1)) • f (0, j) = 0 • f (i, 0) = 0
LCS: memoization char a[1001], b[10001]; /* the two sequence */ int mem[1001][1001]; /* the memory */ memset(mem, -1, sizeof(mem)); /* do it in main method */ int f (int i, int j) { int r; if (mem[i][j] >= 0) return mem[i][j]; if (i == 0 || j == 0) r = 0; else if (a[i] == b[j]) r = 1 + f (i-1, j-1); else r = max(f(i-1, j), f(I, j-1)); mem[i][j] = r; return r; }
LCS: Fill-in-the-Table • F(i, j) depends only on three previous result • f (i-1, j) is the same column on previous row • f (i, j-1) is the previous column on same row • f (i-1, j-1) is the previous column on previous row • We can fill in the mem table row by row • 0th row are all zeros • 0th column are all zeros • fill in mem[i][j] by comparing a[i],b[j] and base on the value of mem[i-1][j] and mem[i][j-1]
LCS: save the memory • Only two rows are needed – the current row and the previous row. • Fill in current row base on previous row • Rotate the role of current and previous row
LCS: Find the Common Subsequnce • By using another table d[i][j] • d[i][j] = 0 if mem[i][j] is calculated base on mem[i-1][j] • d[i][j] = 1 if mem[i][j] is from mem[i][j-1] • d[i][j] = 2 if mem[i][j] is from mem[i-1][j-1] • Construct the sequence using a recursion start at d[m][n] and follow the directory recorded until reach d[0][j] or d[i][0] • TODO: a diagram
LRS: Recursion • Let f (i, j) be the length of longest run start at location (i,j) • Let h (i, j) be the height of location • f (i, j) = 1 + max (f values of reachable neighbors) • Starting from the highest locations
LCS: Fill-in-the-Table • Sort location (i,j) according to h(i, j) in increasing order • Fill in f (i, j) in order based on the value of f (i-1, j), f(i+1, j), f(i, j-1), f(i, j+1)