📜  切割杆| DP-13

📅  最后修改于: 2021-04-29 04:04:45             🧑  作者: Mango

给定一个长度为n英寸的棒,并包含一组价格,其中包含所有小于n的尺寸的价格。确定通过切割杆并出售零件可获得的最大值。例如,如果杆的长度是8,并且不同的值如下所示,则最大可获得值是22(将长度2和6切成两段)

length   | 1   2   3   4   5   6   7   8  
--------------------------------------------
price    | 1   5   8   9  10  17  17  20

如果价格如下,则最大可获得价值为24(切成8个长度为1的片段)

length   | 1   2   3   4   5   6   7   8  
--------------------------------------------
price    | 3   5   8   9  10  17  17  20

一个简单的解决方案是生成所有不同零件的配置并找到价格最高的配置。该解决方案在时间复杂度方面是指数级的。让我们看看这个问题如何同时具有动态编程(DP)问题的重要属性以及如何使用动态编程有效地解决。
1)最佳子结构:
我们可以通过在不同位置进行切割并比较切割后获得的价格来获得最佳价格。我们可以为剪切后获得的片段递归调用相同的函数。
令cutRod(n)为长度为n的棒的要求(最佳价格)值。 cutRod(n)可以编写如下。
对于{0,1 .. n-1}中的所有i,cutRod(n)= max(price [i] + cutRod(ni-1))
2)重叠子问题
以下是杆切割问题的简单递归实现。该实现仅遵循上述递归结构。

C++
// A Naive recursive solution for Rod cutting problem
#include
#include
 
// A utility function to get the maximum of two integers
int max(int a, int b) { return (a > b)? a : b;}
 
/* Returns the best obtainable price for a rod of length n and
   price[] as prices of different pieces */
int cutRod(int price[], int n)
{
   if (n <= 0)
     return 0;
   int max_val = INT_MIN;
 
   // Recursively cut the rod in different pieces and compare different
   // configurations
   for (int i = 0; i


Java
// // A Naive recursive solution for Rod cutting problem
class RodCutting
{
    /* Returns the best obtainable price for a rod of length
       n and price[] as prices of different pieces */
    static int cutRod(int price[], int n)
    {
        if (n <= 0)
            return 0;
        int max_val = Integer.MIN_VALUE;
 
        // Recursively cut the rod in different pieces and
        // compare different configurations
        for (int i = 0; i


Python
# A Naive recursive solution
# for Rod cutting problem
import sys
 
# A utility function to get the
# maximum of two integers
def max(a, b):
    return a if (a > b) else b
     
# Returns the best obtainable price for a rod of length n
# and price[] as prices of different pieces
def cutRod(price, n):
    if(n <= 0):
        return 0
    max_val = -sys.maxsize-1
     
    # Recursively cut the rod in different pieces 
    # and compare different configurations
    for i in range(0, n):
        max_val = max(max_val, price[i] +
                      cutRod(price, n - i - 1))
    return max_val
 
# Driver code
arr = [1, 5, 8, 9, 10, 17, 17, 20]
size = len(arr)
print("Maximum Obtainable Value is", cutRod(arr, size))
 
# This code is contributed by 'Smitha Dinesh Semwal'


C#
// A Naive recursive solution for
// Rod cutting problem
using System;
class GFG {
     
    /* Returns the best obtainable
       price for a rod of length
       n and price[] as prices of
       different pieces */
    static int cutRod(int []price, int n)
    {
        if (n <= 0)
            return 0;
        int max_val = int.MinValue;
 
        // Recursively cut the rod in
        // different pieces and compare
        // different configurations
        for (int i = 0; i < n; i++)
            max_val = Math.Max(max_val, price[i] +
                        cutRod(price, n - i - 1));
 
        return max_val;
    }
 
    // Driver Code
    public static void Main()
    {
        int []arr = new int[] {1, 5, 8, 9, 10, 17, 17, 20};
        int size = arr.Length;
        Console.WriteLine("Maximum Obtainable Value is "+
                                        cutRod(arr, size));
    }
}
 
// This code is contributed by Sam007


PHP


Javascript


C++
// A Dynamic Programming solution for Rod cutting problem
#include
#include
 
// A utility function to get the maximum of two integers
int max(int a, int b) { return (a > b)? a : b;}
 
/* Returns the best obtainable price for a rod of length n and
   price[] as prices of different pieces */
int cutRod(int price[], int n)
{
   int val[n+1];
   val[0] = 0;
   int i, j;
 
   // Build the table val[] in bottom up manner and return the last entry
   // from the table
   for (i = 1; i<=n; i++)
   {
       int max_val = INT_MIN;
       for (j = 0; j < i; j++)
         max_val = max(max_val, price[j] + val[i-j-1]);
       val[i] = max_val;
   }
 
   return val[n];
}
 
/* Driver program to test above functions */
int main()
{
    int arr[] = {1, 5, 8, 9, 10, 17, 17, 20};
    int size = sizeof(arr)/sizeof(arr[0]);
    printf("Maximum Obtainable Value is %dn", cutRod(arr, size));
    getchar();
    return 0;
}


Java
// A Dynamic Programming solution for Rod cutting problem
class RodCutting
{
    /* Returns the best obtainable price for a rod of
       length n and price[] as prices of different pieces */
    static int cutRod(int price[],int n)
    {
        int val[] = new int[n+1];
        val[0] = 0;
 
        // Build the table val[] in bottom up manner and return
        // the last entry from the table
        for (int i = 1; i<=n; i++)
        {
            int max_val = Integer.MIN_VALUE;
            for (int j = 0; j < i; j++)
                max_val = Math.max(max_val,
                                   price[j] + val[i-j-1]);
            val[i] = max_val;
        }
 
        return val[n];
    }
 
    /* Driver program to test above functions */
    public static void main(String args[])
    {
        int arr[] = new int[] {1, 5, 8, 9, 10, 17, 17, 20};
        int size = arr.length;
        System.out.println("Maximum Obtainable Value is " +
                            cutRod(arr, size));
    }
}
/* This code is contributed by Rajat Mishra */


Python
# A Dynamic Programming solution for Rod cutting problem
INT_MIN = -32767
 
# Returns the best obtainable price for a rod of length n and
# price[] as prices of different pieces
def cutRod(price, n):
    val = [0 for x in range(n+1)]
    val[0] = 0
 
    # Build the table val[] in bottom up manner and return
    # the last entry from the table
    for i in range(1, n+1):
        max_val = INT_MIN
        for j in range(i):
             max_val = max(max_val, price[j] + val[i-j-1])
        val[i] = max_val
 
    return val[n]
 
# Driver program to test above functions
arr = [1, 5, 8, 9, 10, 17, 17, 20]
size = len(arr)
print("Maximum Obtainable Value is " + str(cutRod(arr, size)))
 
# This code is contributed by Bhavya Jain


C#
// A Dynamic Programming solution
// for Rod cutting problem
using System;
class GFG {
 
    /* Returns the best obtainable
       price for a rod of length n
       and price[] as prices of
       different pieces */
    static int cutRod(int []price,int n)
    {
        int []val = new int[n + 1];
        val[0] = 0;
 
        // Build the table val[] in
        // bottom up manner and return
        // the last entry from the table
        for (int i = 1; i<=n; i++)
        {
            int max_val = int.MinValue;
            for (int j = 0; j < i; j++)
                max_val = Math.Max(max_val,
                          price[j] + val[i - j - 1]);
            val[i] = max_val;
        }
 
        return val[n];
    }
     
    // Driver Code
    public static void Main()
    {
        int []arr = new int[] {1, 5, 8, 9, 10, 17, 17, 20};
        int size = arr.Length;
        Console.WriteLine("Maximum Obtainable Value is " +
                                        cutRod(arr, size));
         
    }
}
 
// This code is contributed by Sam007


PHP


Javascript


C++
// CPP program for above approach
#include 
using namespace std;
 
// Global Array for
// the purpose of memoization.
int t[9][9];
 
// A recursive program, using ,
// memoization, to implement the
// rod cutting problem(Top-Down).
int un_kp(int price[], int length[],
                    int Max_len, int n)
{
 
    // The maximum priceue will be zero,
    // when either the length of the rod
    // is zero or price is zero.
    if (n == 0 || Max_len == 0)
    {
        return 0;
    }
 
    // If the length of the rod is less
    // than the maximum length, Max_lene will
    // consider it.Now depending
    // upon the profit,
    // either Max_lene  we will take
    // it or discard it.
    if (length[n - 1] <= Max_len)
    {
        t[n][Max_len]
            = max(price[n - 1]
                      + un_kp(price, length,
                           Max_len - length[n - 1], n),
                  un_kp(price, length, Max_len, n - 1));
    }
 
    // If the length of the rod is
    // greater than the permitted size,
    // Max_len we will  not consider it.
    else
    {
        t[n][Max_len]
            = un_kp(price, length,
                              Max_len, n - 1);
    }
 
    // Max_lene Max_lenill return the maximum
    // value obtained, Max_lenhich is present
    // at the nth roMax_len and Max_lenth column.
    return t[n][Max_len];
}
 
/* Driver program to
test above functions */
int main()
{
    int price[] = { 1, 5, 8, 9, 10, 17, 17, 20 };
    int n = sizeof(price) / sizeof(price[0]);
    int length[n];
    for (int i = 0; i < n; i++) {
        length[i] = i + 1;
    }
    int Max_len = n;
 
    // Function Call
    cout << "Maxmum obtained value  is "
         << un_kp(price, length, n, Max_len) << endl;
}


C
// C program for above approach
#include 
#include 
 
int max(int a, int b)
{
  return (a > b) ? a : b;
}
 
// Global Array for the
// purpose of memoization.
int t[9][9];
 
// A recursive program, using ,
// memoization, to implement the
// rod cutting problem(Top-Down).
int un_kp(int price[], int length[],
                     int Max_len, int n)
{
 
    // The maximum priceue will be zero,
    // when either the length of the rod
    // is zero or price is zero.
    if (n == 0 || Max_len == 0)
    {
        return 0;
    }
 
    // If the length of the rod is less
    // than the maximum length, Max_lene
    // will consider it.Now depending
    // upon the profit,
    // either Max_lene  we will take it
    // or discard it.
    if (length[n - 1] <= Max_len)
    {
        t[n][Max_len]
            = max(price[n - 1]
                      + un_kp(price, length,
                              Max_len - length[n - 1], n),
                  un_kp(price, length, Max_len, n - 1));
    }
 
    // If the length of the rod is greater
    // than the permitted size, Max_len
    // we will  not consider it.
    else
    {
        t[n][Max_len]
            = un_kp(price, length,
                             Max_len, n - 1);
    }
 
    // Max_lene Max_lenill return
    // the maximum value obtained,
    // Max_lenhich is present at the
    // nth roMax_len and Max_lenth column.
    return t[n][Max_len];
}
 
/* Driver program to test above functions */
int main()
{
    int price[] = { 1, 5, 8, 9, 10, 17, 17, 20 };
    int n = sizeof(price) / sizeof(price[0]);
    int length[n];
    for (int i = 0; i < n; i++)
    {
        length[i] = i + 1;
    }
    int Max_len = n;
 
    // Function Call
    printf("Maxmum obtained value  is %d \n",
           un_kp(price, length, n, Max_len));
}


输出
Maximum Obtainable Value is 22n

考虑到以上实现,下面是长度为4的Rod的递归树。

cR() ---> cutRod() 

                             cR(4)
                  /        /           
                 /        /              
             cR(3)       cR(2)     cR(1)   cR(0)
            /  |         /         |
           /   |        /          |  
      cR(2) cR(1) cR(0) cR(1) cR(0) cR(0)
     /        |          |
    /         |          |   
  cR(1) cR(0) cR(0)      cR(0)
   /
 /
CR(0)

在上面的部分递归树中,cR(2)被求解两次。我们可以看到,有许多子问题一次又一次地得到解决。由于再次调用了相同的问题,因此此问题具有“重叠子问题”属性。因此,“杆切割”问题具有动态编程问题的两个属性(请参阅此内容)。像其他典型的动态编程(DP)问题一样,可以通过以自下而上的方式构造临时数组val []来避免相同子问题的重新计算。

C++

// A Dynamic Programming solution for Rod cutting problem
#include
#include
 
// A utility function to get the maximum of two integers
int max(int a, int b) { return (a > b)? a : b;}
 
/* Returns the best obtainable price for a rod of length n and
   price[] as prices of different pieces */
int cutRod(int price[], int n)
{
   int val[n+1];
   val[0] = 0;
   int i, j;
 
   // Build the table val[] in bottom up manner and return the last entry
   // from the table
   for (i = 1; i<=n; i++)
   {
       int max_val = INT_MIN;
       for (j = 0; j < i; j++)
         max_val = max(max_val, price[j] + val[i-j-1]);
       val[i] = max_val;
   }
 
   return val[n];
}
 
/* Driver program to test above functions */
int main()
{
    int arr[] = {1, 5, 8, 9, 10, 17, 17, 20};
    int size = sizeof(arr)/sizeof(arr[0]);
    printf("Maximum Obtainable Value is %dn", cutRod(arr, size));
    getchar();
    return 0;
}

Java

// A Dynamic Programming solution for Rod cutting problem
class RodCutting
{
    /* Returns the best obtainable price for a rod of
       length n and price[] as prices of different pieces */
    static int cutRod(int price[],int n)
    {
        int val[] = new int[n+1];
        val[0] = 0;
 
        // Build the table val[] in bottom up manner and return
        // the last entry from the table
        for (int i = 1; i<=n; i++)
        {
            int max_val = Integer.MIN_VALUE;
            for (int j = 0; j < i; j++)
                max_val = Math.max(max_val,
                                   price[j] + val[i-j-1]);
            val[i] = max_val;
        }
 
        return val[n];
    }
 
    /* Driver program to test above functions */
    public static void main(String args[])
    {
        int arr[] = new int[] {1, 5, 8, 9, 10, 17, 17, 20};
        int size = arr.length;
        System.out.println("Maximum Obtainable Value is " +
                            cutRod(arr, size));
    }
}
/* This code is contributed by Rajat Mishra */

Python

# A Dynamic Programming solution for Rod cutting problem
INT_MIN = -32767
 
# Returns the best obtainable price for a rod of length n and
# price[] as prices of different pieces
def cutRod(price, n):
    val = [0 for x in range(n+1)]
    val[0] = 0
 
    # Build the table val[] in bottom up manner and return
    # the last entry from the table
    for i in range(1, n+1):
        max_val = INT_MIN
        for j in range(i):
             max_val = max(max_val, price[j] + val[i-j-1])
        val[i] = max_val
 
    return val[n]
 
# Driver program to test above functions
arr = [1, 5, 8, 9, 10, 17, 17, 20]
size = len(arr)
print("Maximum Obtainable Value is " + str(cutRod(arr, size)))
 
# This code is contributed by Bhavya Jain

C#

// A Dynamic Programming solution
// for Rod cutting problem
using System;
class GFG {
 
    /* Returns the best obtainable
       price for a rod of length n
       and price[] as prices of
       different pieces */
    static int cutRod(int []price,int n)
    {
        int []val = new int[n + 1];
        val[0] = 0;
 
        // Build the table val[] in
        // bottom up manner and return
        // the last entry from the table
        for (int i = 1; i<=n; i++)
        {
            int max_val = int.MinValue;
            for (int j = 0; j < i; j++)
                max_val = Math.Max(max_val,
                          price[j] + val[i - j - 1]);
            val[i] = max_val;
        }
 
        return val[n];
    }
     
    // Driver Code
    public static void Main()
    {
        int []arr = new int[] {1, 5, 8, 9, 10, 17, 17, 20};
        int size = arr.Length;
        Console.WriteLine("Maximum Obtainable Value is " +
                                        cutRod(arr, size));
         
    }
}
 
// This code is contributed by Sam007

的PHP


Java脚本


输出
Maximum Obtainable Value is 22n

上述实现的时间复杂度为O(n ^ 2),这比Naive Recursive实现的最坏情况下的时间复杂度要好得多。

3)使用“无限制背包”的思想。

这个问题与无限制背包问题非常相似,如果同一项目有多次出现,这里是杆的碎片。

现在,我将在“无限制背包”和“杆切割问题”之间进行类比。

C++

// CPP program for above approach
#include 
using namespace std;
 
// Global Array for
// the purpose of memoization.
int t[9][9];
 
// A recursive program, using ,
// memoization, to implement the
// rod cutting problem(Top-Down).
int un_kp(int price[], int length[],
                    int Max_len, int n)
{
 
    // The maximum priceue will be zero,
    // when either the length of the rod
    // is zero or price is zero.
    if (n == 0 || Max_len == 0)
    {
        return 0;
    }
 
    // If the length of the rod is less
    // than the maximum length, Max_lene will
    // consider it.Now depending
    // upon the profit,
    // either Max_lene  we will take
    // it or discard it.
    if (length[n - 1] <= Max_len)
    {
        t[n][Max_len]
            = max(price[n - 1]
                      + un_kp(price, length,
                           Max_len - length[n - 1], n),
                  un_kp(price, length, Max_len, n - 1));
    }
 
    // If the length of the rod is
    // greater than the permitted size,
    // Max_len we will  not consider it.
    else
    {
        t[n][Max_len]
            = un_kp(price, length,
                              Max_len, n - 1);
    }
 
    // Max_lene Max_lenill return the maximum
    // value obtained, Max_lenhich is present
    // at the nth roMax_len and Max_lenth column.
    return t[n][Max_len];
}
 
/* Driver program to
test above functions */
int main()
{
    int price[] = { 1, 5, 8, 9, 10, 17, 17, 20 };
    int n = sizeof(price) / sizeof(price[0]);
    int length[n];
    for (int i = 0; i < n; i++) {
        length[i] = i + 1;
    }
    int Max_len = n;
 
    // Function Call
    cout << "Maxmum obtained value  is "
         << un_kp(price, length, n, Max_len) << endl;
}

C

// C program for above approach
#include 
#include 
 
int max(int a, int b)
{
  return (a > b) ? a : b;
}
 
// Global Array for the
// purpose of memoization.
int t[9][9];
 
// A recursive program, using ,
// memoization, to implement the
// rod cutting problem(Top-Down).
int un_kp(int price[], int length[],
                     int Max_len, int n)
{
 
    // The maximum priceue will be zero,
    // when either the length of the rod
    // is zero or price is zero.
    if (n == 0 || Max_len == 0)
    {
        return 0;
    }
 
    // If the length of the rod is less
    // than the maximum length, Max_lene
    // will consider it.Now depending
    // upon the profit,
    // either Max_lene  we will take it
    // or discard it.
    if (length[n - 1] <= Max_len)
    {
        t[n][Max_len]
            = max(price[n - 1]
                      + un_kp(price, length,
                              Max_len - length[n - 1], n),
                  un_kp(price, length, Max_len, n - 1));
    }
 
    // If the length of the rod is greater
    // than the permitted size, Max_len
    // we will  not consider it.
    else
    {
        t[n][Max_len]
            = un_kp(price, length,
                             Max_len, n - 1);
    }
 
    // Max_lene Max_lenill return
    // the maximum value obtained,
    // Max_lenhich is present at the
    // nth roMax_len and Max_lenth column.
    return t[n][Max_len];
}
 
/* Driver program to test above functions */
int main()
{
    int price[] = { 1, 5, 8, 9, 10, 17, 17, 20 };
    int n = sizeof(price) / sizeof(price[0]);
    int length[n];
    for (int i = 0; i < n; i++)
    {
        length[i] = i + 1;
    }
    int Max_len = n;
 
    // Function Call
    printf("Maxmum obtained value  is %d \n",
           un_kp(price, length, n, Max_len));
}

输出
Maxmum obtained value  is 22