• 15.Dynamic Programming(1)


    DP is a kind of tabular method, like divide-and-conquer method, applying when subproblems overlap.(sharing subsubproblems).

    A DP algorithm solves each subsubproblems only once and then saves its answer in a table.

    A divide-and-conquer algorithm does more work than necessary. It repeatedly solves the subsubproblems.

    15.1 Rod cutting problem

    lenght i 1 2 3 4 5 6 7 8 9 10
    price  pi 1 5 8 9 10 17 17 20 24 30

    For the table above, the optimal solution is:

                                                  image

    Suppose we divide a rod into n pieces, we should have n-1 cuts at the rod. There is 2^(n-1) different cut ways of length n.

    Optimal revenue values of rod n,can be caculated by

                                                                                         

    where .

    We can view ,saying that the first piece has size of i = n, and the remainder has the size n-i=n-n=0 with corresponding revenue .

    As the following arithmetics,we can rewrite the formula above as

                                       

    Algorithms as follows:

    1.naive recursive top-down implementation

    View Code
     1 #include <iostream>
     2  using namespace std;
     3  #include <ctime>
     4  //naive recursive method
     5  int RotCut(int* p, int n)
     6  {
     7      if (n==0)
     8      {
     9          return 0;
    10      }
    11      int i;
    12      int q = INT_MIN;
    13  
    14  
    15      // q=max(p[i]+r[n-i]), p为数组,从0开始
    16      for( i=1; i<=n; i++)
    17      {
    18          int k = p[i-1] + RotCut(p,n-i);
    19          if (q < k)
    20          {
    21              q = k;
    22          }        
    23      }
    24      return q;
    25  }
    26  int main()
    27  {
    28      // p[] = {1,5,8,9,10,17,17,20,24,30}
    29      int p[100] ={1,5,8,9,10,17,17,20,24};
    30      time_t tic = time(NULL);
    31      int k = RotCut(p,25);
    32      time_t toc = time(NULL);
    33      cout<<"optimal value:"<<k<<"  "<<"time: "<<(toc-tic)*1000<<"ms"<<endl;
    34      return 0;
    35  }

        The results run by this program is listed as follows:

    n 4 8 20 25 30
    optimal val 10 22 56 69 85
    run time 0 0 0 1s 27s

        This recursive CUT_ROD is very inefficient, cause it calls itself over and over with the same parameter values, that is ,it solve the same subproblems repeatedly.For example, figure follows illustrates what happens when n is 4.The running time of CUT-ROD is exponential in n.

                                                           image

    2.DP for optimal rod cutting

           Using DP can convert CUT-ROD into an efficient algorithm, making

           DP solves each subproblems only once by using additional memory to improve efficiency.There are two equivalent ways to implement DP algorithm: (1)top-down with memoization and (2)bottom-up method.

    (1) Top-down with memoization

    Recursively anyway, but save the result of each subproblem ( n subproblems ) in an array  r[] initial with 0s or a hash table. The array is used for check wether a subproblem was solved, if the ith subproblem was solved, its value was stored in r[i] > 0.

    View Code
     1 #include <iostream>
     2 using namespace std;
     3 #include <ctime>
     4 const int MAXiSIZE=2000;
     5 //Top-down with memoization method
     6 int MemoizedCutRodAux(int *p, int n, int *r)
     7 {     //using an addition array r[] to store optimal subproblems value
     8     if ( r[n] >= 0)
     9         return r[n];
    10     int q,i,k;
    11     if ( n == 0)
    12     {
    13         q = 0;
    14     }
    15     else 
    16     {
    17         q = INT_MIN;// iter method
    18         for ( i=1; i<=n; i++)
    19         {
    20             k = p[i-1] + MemoizedCutRodAux(p,n-i,r);
    21             if ( q<k )
    22                 q =k;                    
    23         }
    24     }
    25     r[n] = q;
    26     return q;    
    27 }
    28 
    29 int MemoizedCutRod(int *p, int n)
    30 {
    31     int i;
    32     int r[MAXiSIZE];//auxiliary array initialized with minimum
    33     for ( i=0; i<=n; i++)
    34     {
    35         r[i] = INT_MIN;    
    36     }
    37     return MemoizedCutRodAux(p,n,r);
    38 }
    39 int main()
    40 {
    41     // p[] = {1,5,8,9,10,17,17,20,24,30}
    42     int p[MAXISIZE] ={1,5,8,9,10,17,17,20,24};
    43     /*time_t tic = time(NULL);
    44     int k = RotCut(p,25);
    45     time_t toc = time(NULL);
    46     cout<<"optimal value:"<<k<<"  "<<"time: "<<(toc-tic)*1000<<"ms"<<endl;*/
    47     
    48     clock_t start = clock();
    49     int k = MemoizedCutRod(p,1000);
    50     clock_t end = clock();
    51     cout<<"optimal value:"<<k<<"  "<<"time: "<<double(end-start)/CLOCKS_PER_SEC<<"s"<<endl;
    52     //int k = BottomUpCutRod(p,40);
    53     //cout<<k<<endl;
    54 
    55     //SolutionOfCutRod(p,40);
    56     return 0;
    57 }
    n 4 20 30 1000 1999
    optimal val 10 56 85 2832 INT_MAX
    run time 0 0 0 0.015s 0.047s

    (2)bottom-up method

      Not recursively, but iteratively.  Solve the subproblems by size and solve them in size order, smallest first.

    View Code
     1 #include <iostream>
     2 using namespace std;
     3 #include <ctime>
     4 const int MAXiSIZE=2000;
     5 int BottomUpCutRod(int *p, int n)
     6 {
     7     int r[MAXiSIZE];//auxiliary array initialized with minimum
     8     r[0] = 0;
     9     
    10     int i,j,k;
    11     for ( j=1; j<=n; j++)
    12     {
    13         int q = INT_MIN;
    14         for ( i=1; i<=j; i++)
    15         {
    16             k = p[i-1] + r[j-i];
    17             if ( q < k )
    18                 q = k;
    19             r[j] = q;
    20         }
    21     }
    22     return r[n];
    23 }
    24 int main()
    25 {
    26     // p[] = {1,5,8,9,10,17,17,20,24,30}
    27     int p[MAXISIZE] ={1,5,8,9,10,17,17,20,24};
    28 
    29     clock_t start = clock();
    30     //int k = MemoizedCutRod(p,1999);
    31     int k = BottomUpCutRod(p,40);
    32     clock_t end = clock();
    33     cout<<"optimal value:"<<k<<"  "<<"time: "<<double(end-start)/CLOCKS_PER_SEC<<"s"<<endl;
    34 
    35     return 0;
    36 }
    n 4 20 30 1000 1999
    optimal val 10 56 85 2832 INT_MAX
    run time 0 0 0 0 0.016s

      

    3.Solution

    Easy part for this example, only need a list store every piece size.

    Solution
     1 #include <iostream>
     2 using namespace std;
     3 #include <ctime>
     4 const int MAXiSIZE=2000;
     5 int ExtendedBottomUpCutRod(int *p, int n, int* r, int *s)
     6 {
     7     
     8     int i,j,k;
     9     for ( j=1; j<=n; j++)
    10     {
    11         int q = INT_MIN;
    12         for ( i=1; i<=j; i++)
    13         {
    14             k = p[i-1] + r[j-i];
    15             if ( q < k )
    16             {
    17                 q = k;
    18                 s[j] = i;// here is the add item
    19             }
    20             r[j] = q;
    21             
    22         }
    23     }
    24     return r[n];
    25     
    26 }
    27 
    28 int SolutionOfCutRod(int *p, int n)
    29 {
    30     int s[MAXiSIZE],r[MAXiSIZE];
    31     r[0] = 0;
    32 
    33     ExtendedBottomUpCutRod(p,n,r,s);
    34     cout<<"value of solution: "<<r[n]<<endl<<"solution:";
    35     while ( n>0 )
    36     {
    37         cout<<s[n]<<" ";
    38         n = n - s[n];
    39     }
    40     cout<<endl;
    41     return r[n];
    42 
    43 }
    44 
    45 int main()
    46 {
    47     // p[] = {1,5,8,9,10,17,17,20,24,30}
    48     int p[MAXISIZE] ={1,5,8,9,10,17,17,20,24};
    49     
    50     SolutionOfCutRod(p,40);
    51     return 0;
    52 }

     image

  • 相关阅读:
    [51nod1247]可能的路径(思维题)
    天梯赛L1020 帅到没朋友(map的使用)(模拟,数组非排序去重)
    洛谷 p1030 树的遍历
    天梯赛L1046 整除光棍(模拟)
    牛客,并查集,简单dp经商
    天梯赛L1043 阅览室 模拟题
    天梯赛L1049(模拟+vector的使用)
    天梯赛L1011,简单模拟
    codeforces 1201 c
    天梯赛L2003月饼(简单排序题)
  • 原文地址:https://www.cnblogs.com/baiweiguo/p/2841055.html
Copyright © 2020-2023  润新知