【算法学习】切割木棍问题——动态规划

问题描述:

假设,有一条长度为n的木棍,已知木棍的销售价格Pi与木棍长度i有关,i = 1,2,3,…n.问,怎样切割能获得最大收益。

长度为0的木棍收益肯定是0了,即profit[0] = 0.

切割长度(seg)12345678910
销售价格(pi)1589101717202430

对于长度为n的木棍,他的递推关系是:profit[n] = max(pi[i] + profit[length – seg[i]]), 其中i = 1,2,3,…n;

暴力解决方法:

int Cut_Common(int seg[], int pi[], int arr_len, int source_len)
{
    if (source_len == 0)
        return 0;
	int tmp = -1;
	for (int i = 0; i < arr_len; ++i)
	{
        if (source_len - seg[i] >= 0)
		    tmp = max(tmp, pi[i] + Cut_Common(seg, pi, arr_len, source_len - seg[i]));
	}
	return tmp;
}

这样的解法,
会发生多次相同的自问题求解,故效率非常差。联想每次调用产生一个树节点,叶节点代表了结束递归,O(2^n)的时间复杂度

为了解决对相同自问题的多次求解,故可用一个数组储存自问题的解,下次需要时就不用再从新算。

动态规划——自底向上方法

int _Cut_Dynamic_DownToTop(int seg[], int pi[], int arr_len, int length, int dump[])
{
    int tmp;
    dump[0] = 0;
    for (int i = 1; i <= length; ++i)
    {
        tmp = -1;   
        for (int j = 0; j < arr_len; ++j)
        {
            if (i - seg[j] >= 0)
                tmp = max(tmp, pi[j] + dump[i - seg[j]]);               
        
        }
        dump[i] = tmp;

    }
    return dump[length];
}

int Cut_Dynamic_DownToTop(int seg[], int pi[], int arr_len, int length)
{
    int *dump = (int *)malloc(sizeof(int)*length + 1);
    int tmp = _Cut_Dynamic_DownToTop(seg, pi, arr_len, length, dump);
    free(dump);
    return tmp;
}

解决的主要思路是,先求解长度为1的最大收益,再到2,3…..一直到n,而每次求解的解都储存起来,时间复杂度为O(nm),空间复杂度为O(n)。

自底向上的解法仍有瑕疵,那就是在求解给定问题时,有些较小问题的解常常是不必须的,而自顶向下 + 记忆功能 解决了这个问题。

动态规划——自顶向下(+记忆功能):

int _Cut_Dynamic_TopToDown(int seg[], int pi[], int arr_len, int length, int dump[])
{
    if (dump[length] >= 0)
        return dump[length];
    int tmp = -1;
    for (int i = 0; i < arr_len; ++i)
    {
        if (length - seg[i] >= 0)
            tmp = max(tmp, pi[i] + _Cut_Dynamic_TopToDown(seg, pi, arr_len, length-seg[i], dump));
    }
    dump[length] = tmp;
    return dump[length];
}

int Cut_Dynamic_TopToDown(int seg[], int pi[], int arr_len, int length)
{
    int *dump = (int *)malloc(sizeof(int)*length+1);
    for (int i = 0; i <= length; ++i)
    {
        dump[i] = -1;
    }
    dump[0] = 0;
    int tmp = _Cut_Dynamic_TopToDown(seg, pi, arr_len, length, dump);
    free(dump);
    return tmp;
}

注意到,自顶向下 和 暴力解决的 细微差别,自顶向下记录了每一步的结果(这就是记忆功能),而暴力解决方法总是重新算结果。

    原文作者:动态规划
    原文地址: https://blog.csdn.net/jammg/article/details/51589662
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞