算法导论之钢条切割

算法导论之钢条切割

对动态规划问题一直理解不够透彻,先从简单的例子开始学习动态规划原理。


问题:

Sering 公司购买长钢条,将其切割为短钢条出售。切割工序本身没有成本支出。公司的管理层希望知道最佳的切割方案。

假定我们知道Serling公司出售一段长度为i英寸的钢条的价格为  (i=1,2,...,单位为美元)。钢条的长度均为英寸钢条和长度价格表如表1所示。

表1

钢条和长度 价格表:

长度价格
1$1
2$5
3$8
4$9
5$10
6$17
7$17
8$20
9$24
10$30

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

计算机程序一次只能比较2个数的大小,有大于,等于,小于三种情况。对于钢条来说,假定我们一次切割一次将钢条切割成2段,如果切割成大于2段(没有想清楚)。

可以分为以下三种情况:
1)假定一段是待售的,另一段是待切割的。
2)假定两段都是待售的。
3)假定两段都是待切割的。
情况3可以明显的看出这种思路不能求解出最优解,这种思路作废。对于情况2,这种方式不能求出解,对于一个算法来说需要能够求出子问题,而不是递归的划分成子问题。

思路1)从初始值开始
符号定义:
定义 Vi 为i英寸所能销售的最大价格
假设一个0英寸的钢条,可以切为0英寸,价值为0美元。
假定一个1英寸的钢条,可以切割为1英寸和0英寸,价值为1美元。
假定一个2英寸的钢条,可以切割为(2英寸和0英寸)、(1英寸和1英寸),在这两种方案中选择 V2=5 美元。
假定一个3英寸的钢条,可以切割为(3英寸和0英寸),(2英寸和1英寸),(3个1英寸的方案),在这种方案中选择,可以得出 V3=8 美元。
假定一个n英寸的钢条。可以切割为(n英寸和0英寸),(n-1英寸和1英寸)…等方案。
假定第一段用于出售,第二段用于继续切割,那么这个问题可以归纳为
Vn=max{Pi+Vni},i=1,2,...n 式子(1)

程序设计思路
数据结构定义
P数组用于保存价格
V数组用于保存各种长度的钢条所能售出的最大价格。
C数组用于保存各种长度的钢条切割第一段的待售的长度。
从式子1可以看出长度长的钢条求最大销价格需要较短的钢条的求解结果。
从钢条长度为1计算到要求的钢条长度的值,再将此问题分解为小问题遍历所有的可能性进行求解,假定要求的钢条长度为n,程序设计思路如下(伪代码):

//初始化
P = 价格表
V = 0
C = 0
//求解最优值
for i=1:n
{
    for(j=1:i)
    {
        if(V[i] < V[j] + P[i-j])
        {
            V[i] = V[j] + P[i-j]
            C[i] = i-j;
        }
    }
}
//输出最优值
//最大销售价格
V[n]
//最优解输出
cLength = n

while cLength>0
    C[cLength]
    cLength -= C[cLength]

java 程序代码如下:

package stellCut;

public class Cut {

    public static void main(String[] args)
    {
        //cutStell(10);
        //cutStell(8);
        cutStell(25);
    }

    //要切割钢条的长度
    public static void cutStell(int length)
    {
        int[] V = new int[length+1];
        int[] C = new int[length+1];

        for(int i=1;i<=length;i++)
        {
            for(int j=0;j<i;j++)
            {
                if(V[i] < getPrice(i-j) + V[j])
                {
                    V[i] = getPrice(i-j) + V[j];
                    C[i] = i-j;
                }
            }
        }

        //ouput the value of cut steel
        System.out.println("max value is:" + V[length]+"$");
        int cl = length;
        while(cl>0)
        {
            System.out.print(" "+ C[cl] +" ");
            cl = cl-C[cl];
        }
    }

    //长度价格查询
    public static int [] P = {0,1,5,8,9,10,17,17,20,24,30};

    public static int getPrice(int length)
    {
        if(length>10)
            return -1;
        else
            return P[length];
    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值