• 钢条切割问题


    突然发现,钢条切割竟然没有写。

    假设公司出售一段长度为i英寸的钢条的价格为Pi(i = 1, 2, ...单位:美元),下面给出了价格表样例:

    长度i     1     2     3  4  5   6     7  8   9  10

    价格Pi  1     5     8  9  10   17   17  20   24  30

    切割钢条的问题是这样的:给定一段长度为n英寸的钢条和一个价格表Pi,求切割方案,使得销售收益Rn最大。

    当然,如果长度为n英寸的钢条价格Pn足够大,最优解可能就是完全不需要切割。

    对于上述价格表样例,我们可以观察所有最优收益值Ri及对应的最优解方案:

    R1 = 1,切割方案1 = 1(无切割)

    R2 = 5,切割方案2 = 2(无切割)

    R3 = 8, 切割方案3 = 3(无切割)

    R4 = 10, 切割方案4 = 2 + 2

    R5 = 13, 切割方案5 = 2 + 3

    R6 = 17, 切割方案6 = 6(无切割)

    R7 = 18, 切割方案7 = 1 + 6或7 = 2 + 2 + 3

    R8 = 22, 切割方案8 = 2 + 6

    R9 = 25, 切割方案9 = 3 + 6

    R10 = 30,切割方案10 = 10(无切割)

    更一般地,对于Rn(n >= 1),我们可以用更短的钢条的最优切割收益来描述它:

    Rn = max(Pn, R1 + Rn-1, R2 + Rn-2,...,Rn-1 + R1)

    首先将钢条切割为长度为i和n - i两段,接着求解这两段的最优切割收益Ri和Rn - i

    (每种方案的最优收益为两段的最优收益之和),由于无法预知哪种方案会获得最优收益,

    我们必须考察所有可能的i,选取其中收益最大者。如果直接出售原钢条会获得最大收益,

    我们当然可以选择不做任何切割。

    分析到这里,假设现在出售8英寸的钢条,应该怎么切割呢?

    下面给出三种方法:

    1、自顶向下;

    2、带备忘的自顶向下

    3、由底向上

    其中由底向上最简单也最高效。大家可以尝试将钢管长度设大些,比较不同方法之间的运行速度差异。通过对比,可以加深对动态规划的思想的了解与记忆。

    给出例子:对于自顶向下钢条收益按照上述要求,那么可以计算钢条长度在30以下。(效率很低)

    对于带备忘的自顶向下,可以计算钢条长度在10000以内。

    对于自底向上,可以计算钢条长度在30000以内。(上述范围仅供参考)

    代码:

     1 #include <bits/stdc++.h>
     2 #define min_num -100010
     3 #define max_size 100010
     4 int p[max_size];
     5 int r[max_size];
     6 using namespace std;
     7 //****************自顶向下递归实现***************
     8 double cut_rod(int p[],int n){
     9     if(n==0) return 0;
    10     double q=min_num;
    11     for(int i=1;i<=n;i++){
    12         q=max(q,p[i]+cut_rod(p,n-i));
    13     }
    14     return q;
    15 }
    16 //****************带备忘的自顶向下******************//
    17 int memoized_cut_rod_aux(int p[],int n,int r[]){
    18     int q=0;
    19     if(r[n]>=0)
    20         return r[n];
    21     if(n==0)
    22         q=0;
    23     else q=min_num;
    24     for(int i=1;i<=n;i++){
    25         q=max(q,p[i]+memoized_cut_rod_aux(p,n-i,r));
    26     }
    27     r[n]=q;
    28     return q;
    29 }
    30 
    31 int memoized_cut_rod(int p[],int n){
    32     for(int i=0;i<=n;i++){
    33         r[i]=min_num;
    34     }
    35     return memoized_cut_rod_aux(p,n,r);
    36 }
    37 
    38 //**********自底向上的算法******//
    39 int bottom_up_cut_rod(int p[],int n){
    40     for(int i=0;i<=n;i++){
    41         r[i]=0;
    42     }
    43     int q;
    44     for(int j=1;j<=n;j++){
    45         q=min_num;
    46         for(int i=1;i<=j;i++){
    47             q=max(q,p[i]+r[j-i]);
    48         }
    49         r[j]=q;
    50     }
    51     return r[n];
    52 }
    53 //**********测试函数************//
    54 int main(){
    55     int num;
    56     cout<<"请输入钢条收益num:"<<endl;
    57     cin>>num;
    58     for(int i=1;i<=num;i++){
    59             scanf("%d",&p[i]);
    60         }
    61     int n;
    62     cout<<"请输入钢条长度:
    ";
    63     while(~scanf("%d",&n)){
    64         //cout<<"最大收益是:"<<cut_rod(p,n)<<endl;//自顶向下的递归算法
    65         //cout<<"最大收益是:"<<memoized_cut_rod(p,n)<<endl;//带备忘的自顶向下
    66         cout<<"最大收益是:"<<bottom_up_cut_rod(p,n)<<endl;//自底向上的算法
    67         cout<<"请输入钢条长度:
    ";
    68     }
    69 }
  • 相关阅读:
    Servlet 的生命周期
    关于JSP
    JQuery事件绑定
    JavaScript中操作元素
    javaScript的函数使用
    Servlet 的API
    JavaScript中BOM对象
    gridview 绑定时间列 取短日期
    A4纸网页打印中对应像素的设定和换算
    动态添加 控件 并获取值
  • 原文地址:https://www.cnblogs.com/zpfbuaa/p/4986169.html
Copyright © 2020-2023  润新知