Dynamic Programming (I)

1. Dynamic Programming

  Generally speaking, Dynamic Programming (DP) is an algorithmic paradigm where we solve an optimization problem with optimal structure in a bottom-up way to avoid overlapping sub-problems. According to CLRS, a problem exhibits optimal structure if you need to find the solution to its sub-problems before accomplishing the whole optimization problem. In this sense, every problem that can be solved by DP is based on a DAG structure, where each node is a sub-problem and a sub-problem can be solved only if its preceding sub-problems have been solved.

  We refuse to solve the DP problems in a recursive way in that we will be faced with a lot of overlapping sub-problems, which render such solution awfully inefficient. Usually, we choose to sacrifice space in order to save time when we exploit the optimal structure of an optimization problem. Moreover, there are some space compression techniques to minimize the cost of a solution. 


2. Knapsack Problems

  About the description of Knapsack Problems, please refer to wikipedia.

  (1)  Here is my solution to Knapsack with repetition:

 1     public static int solve(int num, int vol)   {
 2         // Here we use DP to solve Unbounded Knapsack Problem
 3         // Precondition: cost[] and value[] are the weights and values
 4         //            of the num objects respectively
 5         // Postcondition: the maximum value that a knapsack with 
 6         //            capacity vol can contain is returned
 7         int[] dp = new int[vol+1];
 8         for (int i=0;i<=vol;i++){
 9             // Solve the problem in a bottom-up way, so that
10             //        for all j<=i dp[j] will be the max value that a knapsack
11             //        of capacity v can contain
12             for (int j=0;j<=num;j++){
13                 if (cost[j]<=i && dp[i-cost[j]]+value[j]>dp[i]) {
14                     dp[i] = dp[i-cost[j]]+value[j];
15                 }
16             }
17         }
18         return dp[vol];
19     }

  (2)  This is my solution to Knapsack without repetition:

 1     public static int solve(int num,int vol)  {
 2         // Here we use DP to solve 0 - 1 Knapsack Problem
 3         // Precondition: cost[] and value[] are the weights and values
 4         //            of the num objects respectively
 5         // Postcondition: the maximum value that a knapsack with 
 6         //            capacity vol can contain is returned
 7         int [][] dp = new int[vol+1][num+1];
 8         //     dp[i][j] will be the max value that a knapsack of capacity i
 9         //            can contain by choosing objects from 0 to j-1
10         // Basic Cases:    dp[i][j] = 0, for all (i==0||j==0)
11         for (int j=1;j<=num;j++) {
12             for (int i=1;i<=vol;i++) {
13                 dp[i][j] = dp[i][j-1];
14                 if (cost[j-1]<=i && dp[i-cost[j-1]][j-1]+value[j-1]>dp[i][j]) {
15                     dp[i][j] = dp[i-cost[j-1]][j-1]+value[j-1];
16                 }
17             }
18         }
19         return dp[vol][num];
20     }

3. Maximum Sum of Consecutive Subsequence

  Many dynamic programming problems relies on a recursive structure like sequences, such as the classical Longest Common Subsequence introduced in CLRS. In this section, I wish to offer my solution to POJ 2479, a problem that requires to calculate the maximum sum among all the consecutive sub-sequences of a given integer sequence.

 1 import java.util.*;
 2 
 3 public class Main {
 4     public static Scanner in;
 5     public static int num;
 6     public static int [][] dp;
 7     
 8     public static long maxSum()  {
 9         for (int i=1;i<num;i++) {
10             // Invariant: for j<=i, dp[j][0] will be the max
11             //        sum of all the sub-sequences ending at j
12             if (dp[i-1][0]>0) {
13                 dp[i][0]+=dp[i-1][0];
14             }
15         }
16         for (int i=1;i<num;i++) {
17             // Invariant: for j<=i, dp[j][0] will be the max
18             //        sum of all the sub-sequences whose ending
19             //        index is no larger than j
20             if (dp[i-1][0]>dp[i][0]) {
21                 dp[i][0] = dp[i-1][0];
22             }
23         }
24         for (int i=num-2;i>=0;i--) {
25             // Invariant: for j>=i, dp[j][0] will be the max
26             //        sum of all the sub-sequences starting at j
27             if (dp[i+1][1]>0) {
28                 dp[i][1]+=dp[i+1][1];
29             }
30         }
31         for (int i=num-2;i>=0;i--) {
32             // Invariant: for j>=i, dp[j][0] will be the max
33             //        sum of all the sub-sequences whose starting
34             //        index is no less than j
35             if (dp[i+1][1]>dp[i][1]) {
36                 dp[i][1] = dp[i+1][1];
37             }
38         }
39         int val = dp[0][0]+dp[num-1][1];
40         for (int i=1;i<num;i++) {
41             if (dp[i-1][0]+dp[i][1]>val) {
42                 val = dp[i-1][0]+dp[i][1];
43             }
44         }
45         return val;
46     }
47     public static void main(String[] args) {
48         in = new Scanner(System.in);
49         dp = new int [50000][2];
50         int t = in.nextInt();
51         String line; StringTokenizer str;
52         for (int i=0;i<t;i++) {
53             num = in.nextInt();
54             in.nextLine();        // skip the newline symbol
55             line = in.nextLine();     // nextInt() is too time-consuming
56             str = new StringTokenizer(line);
57             for (int j=0;j<num;j++) {
58                 dp[j][0] = dp[j][1] = Integer.parseInt(str.nextToken());
59             }
60             System.out.println(maxSum());
61         }
62         in.close();
63     }
64 }

References:

  1. Cormen, T. H. et al. Introduction to Algorithms[M].北京:机械工业出版社,2006-09
  2. Dasgupta, Sanjoy, Christos Papadimitriou, and Umesh Vazirani. Algorithms[M].北京:机械工业出版社,2009-01-01

原文地址:https://www.cnblogs.com/DevinZ/p/4411444.html