动态规划之钢条切割问题


在看这张之前,最好看看我写的动态规划详解,里面都是讲理论基础,我下面的分析都是在此基础上进展的。

钢条切割问题:

给定一段长度为n英寸的钢条和一个价格表Pi( i=1, 2, ..., n ),求切割钢条方案,使得销售收益最大.

例如:

长度i
12345678910
价格Pi1589101717202430

依旧根据DP算法四个步骤来分析:
①.描述最优解的结构。

首先求解这些问题要用到递归思想为铺垫,因此将元素个数从n向下开始考察。长度为n,首先做一次选择,在第i个位置上切割一次,并假定为最优解。此时最优解由(1->i)和(i+1 ->n)两个子问题的最优解来实现。可以写出Rn=max(Ri+Rn-i),1<=i<=n且R0=0。通过分析可知求解全部子问题为R1+Rn-1,....,Rn-1+R1,Rn。很多是对称的,因此表达式可以优化为Rn=max(Pi+Rn-i),1<=i<=n且R0=0。对于每一个i值,只需求解一个子问题Rn-i即可。


②.递归定义最优解的值。

上面已经给出了表达式Rn=max(Pi+Rn-i),1<=i<=n且R0=0。根据此表达式来构造备份数组以及重构最优值数组。并根据此表达式编写程序。
③.按自底而上的方式计算最优解的值。

先定义备份数组,由于表达式右边是Rn-i,需要的是长度为n-i时的最优值,因此定义数组R[n],保存长度为i时的最优值。
④.由计算出的结果创造一个最优解。

为了构造最优值,就要保存切割信息,当求长度为j的Rj=max(Pi+Rj-i)时,i从1到j。由于是求最大值,因此保存Rj取得最大值是的切割点i。并且写代码是,这种求最大值最小值,可以先设置一个中间变量,如果每一次遍历求解的值先保存在中间变量中,当中间变量更优时,更新备份数组。此时也更新切割结点。


自顶向下的方法:不带备忘和带备忘

//自顶向下的递归
CUT-ROD(p,n)
{
    if(n==0)
        return 0;
    temp = q =-1000;
    for(int i=1;i<=n;i++){  //取值范围由递归表达式的变量范围而来
        temp = p[i]+CUT-ROD(P,n-i); //求解max()问题,转化成先存储在一个临时变量里面,然后再更新
        if(temp > q)
            q = temp;
    }
    return q;
}


//带备份的自顶向下的递归
MEMOIZED-CUT-ROD(p,n)
{
    int r[n+1];
    for(int i=0;i<=n;i++)
        r[i] = -10000;
    return MEMOIZED-CUT-ROD-AUX(p,n,r);
}

MEMOIZED-CUT-ROD-AUX(int p[],int n,int r[])
{
    if(r[n]>=0)         //不同点1,入口时就判断存储值是否有效。有效立即返回
        return r[n];
    if(n==0)            //这里是对r[0]赋值,之后r[0]的返回有上面语句来完成。
        q = 0;
    else{
        q = -10000;
        for(int i=1;i<=n;i++){  //遍历形式与普通递归方法一模一样
            temp = p[i] + MEMOIZED-CUT-ROD-AUX(p,n-i,r);
            if(temp > q)
                q = temp;
        }
    }
    r[n] = q;   //不同点2,出口时,对数组存储进行更新。
    return r[n];
}


自底向上的方法

//自底向上的方法
BOTTOM-UP-CUT-ROD(p,n)
{
    int r[n+1],s[n+1];
    r[0] = 0;   //对基本的一定要赋值!最安全的做法是将整个数组初始化为合适值0、正无穷、负无穷
    for(int j=1;j<=n;j++){
        q = -10000;
        for(int i=1;i<=j;i++){
            if(q < p[i]+r[n-i]){
                q = p[i]+r[n-i];
                s[j] = i;
            }
        }
        r[j] = q;
    }
    return r[]and s[];
}


输出切割方案

//输出切割方案
PRINT-CUT-ROD-SOLUTION(p,n)
{
    (r,s) = BOTTOM-UP-CUT-ROD(p,n);
    while(n){
        print s[n];
        n = n-s[n];
    }
}



  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值