剑指offer-动态规划-剪绳子问题分析

题目:给你一根绳子长度为n,请把绳子剪成m段(m、n都是整数,n>1且m>1),每段绳子的长度记为k[0],k[1],...k[m]。请问k[0]xk[1]x...xk[m]可能的最大乘积是多少?

先把代码附上:

int maxProductAfterCutting_solution1(int length)
{
//为了应对直接要求输出,做出的判断
    if(length < 2)
        return 0;
    if(length == 2)
        return 1;
    if(length == 3)
        return 2;

    int* products = new int[length + 1];

//为了求后续长度做准备,相当于前面例子中的材料。
    products[0] = 0;
    products[1] = 1;
    products[2] = 2;
    products[3] = 3;

    int max = 0;
    for(int i = 4; i <= length; ++i) //这里的i就是绳子的长度
    {
        max = 0;
        for(int j = 1; j <= i / 2; ++j)
        {
            int product = products[j] * products[i - j]; //进行划分
            if(max < product)   //寻找乘积最大的那一组
                max = product;

            products[i] = max;
        }
    }

    max = products[length];
    delete[] products;

    return max;
}

我们先理解一下什么是动态规划:

1.所要解决的问题是寻找给定情况下的最优解

2.整体问题的最优解依赖于子问题的最优解

举个例子:你想造一辆世界上最好的跑车,那么你是不是需要用到世界上最好的零件呢?零件要世界最好,那么你的制造工艺是不是要世界第一呢?等等依次递归下去...

3.大问题分解成小问题,小问题之间存在着重叠的问题

继续上面的例子,你需要最好的零件,假设这些零件为A、B、C,它们制造工艺不一样,但是它们的原材料却是一样的,这个时候我们只需要掌握不同的制造工艺就行,至于原材料都是一样的,就不必为材料的事情操心了。

4.从上往下分析,从下往上解决,将底层最优解存储起来。

先从整体分析问题在纠结细节,这是我们解决问题的常用手法。还是拿跑车的例子说事,当你想要造一辆跑车,你会一上来就想到怎么设计跑车的发动机的吗?

下面我们用动态规划的思想来分析这个问题:

一开始把长为n的绳子丢给你,你肯定懵逼的,因为第一刀下去就有n-1种可能性,我怎么知道切哪好。做个假设,n=100,假如..恩经过我的计算,划分成50-50可以最大,49-51次之。但是你只能确定这一刀下去在第一刀时候最大,你无法保证后续在n=50的绳子中一定能够划分出 比 在n=49的绳子中划分出的长度 更长。要确保每一刀下去都是朝着最大值的方向前进,那么每一刀都得先预知我剪下之后一定是最大,就像前面有人指引你往哪里剪。

还得明白一点就是,我们划分出来的绳子长度和我们要求的绳子长度是不一样的。如一开始就要你求n=2,这个时候f(2)=1x1=1(题目要求必须切一刀),但如果是我们划分出来的长度就不一样了,因为已经剪了x刀了,如f(5)=f(2)xf(3) 这个时候你还会傻傻的把n=2的绳子再剪一刀变得更短吗?

我们先做如下设定  f(0)=0    f(1)=1   f(2)=2    f(3)=3    因为这几个长度较特殊的情况,因为很容易就划分出这几个长度。

n=4 f(4)=max{ f(1)xf(3),   f(2)xf(2), f(3)xf(1) <多余重复,这就是j=i/2 的原因> }=4

n=5 f(5)=max{f(1)xf(4), f(2)xf(3)}=6

n=6 f(6)=max{f(1)xf(5), f(2)xf(4),f(3)xf(3) }=9

f(n)= max{f(1)xf(n-1),  f(2)xf(n-2),  f(3)xf(n-3) ......}

每一步决策都依赖于之前的判断(也就是更小层次的问题的最优解)

按照这个规律你知道应该怎么求长度为n的绳子怎么剪能取得乘积最大了吧? 

 

 

你可能感兴趣的:(算法题)