• 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

  • 相关阅读:
    线性代数回顾+深化(未完成版)
    HIT OS2020 Spring Lab2
    选择
    工业互联网
    leetcode-200 岛屿数量
    记网易面试题<二>
    记网易面试题《一》
    leetecode-14-最长公共子串-简单
    leetcode-1012 至少有1位重复的数字
    协程
  • 原文地址:https://www.cnblogs.com/DevinZ/p/4411444.html
Copyright © 2020-2023  润新知