动态规划算法

1 动态规划的思想
动态规划也是采取的分治的思想,关键点就在于怎么去分。
在钢管分割的问题上,可以这样去思考问题,假设钢管长度为N,最优解是将其分割为k段。那么当将钢管分割为2段时,
我们假设x = L(1) + L(2) + ... + L(p), y = L(p+1) + L(p+2) + ... + L(k)。则必然是L(1) + L(2) + ... + L(p)是
长度为x的最优解,L(p+1) + L(p+2) + ... + L(k)是长度为y的最优解。证明方法很简单,采取反证的思想,如果
L(1) + L(2) + ... + L(p)不是长度为x的最优解,那么L(1) + L(2) + ... + L(p) + L(p+1) + L(p+2) + ... + L(k)必然
不是长度为n的最优解。
所以说将n分割为x+y的时候,并且通过一定次数的继续分割,必然会产生诸如L(1) + L(2) + ... + L(p) + L(p+1) + L(p+2) + ... + L(k)
的最优解。也就是说可以通过2分法来产生最优解,但是2分法的两个局部最优解的和就不一定是全局最优解了。


根据以上思想,可以得出钢管最优解的一个递归公式
r(n) = max(pn,(r1 + r(n-1)),(r2 + r(n-2)),...(r(n-1), r1));

2 问题的简化
可以这么想,将钢条分为两段,第一段的长度依次递加,那么所以递归式可以简化为:
r(n) = max(pi + r(n-i)), 1<=i<=n;

3 问题的解决
<1>直接用根据递推公式建立递归函数
这样的缺点就是会重复计算价值,造成资源的浪费
<2>建立起包含价值数组的递归函数
这是针对<1>的缺点,加入了价值数组,那么在用到长度为n的最大价值时候,如果r[n]已经存在,就不需要再次求解
<3>自底向上的迭代方法求解
这个比较简单和容易实现,它是不断的根据已经有的解来求解未知的解,从而得到最终的答案


4 代码实现
#include <iostream>
#include <algorithm>
#include <vector>


int cutRod(int* p, int n);


int memoryCutRod(int* p, int n);
int memoryCutRodAux(int* p, int n, std::vector<int>& r);


int bottomUpCutRod(int*p, int n);


int main()
{
	int p[10] = {1,5,8,9,10,17,17,20,24,30};
	int n = 4;


	//first method
	int r = cutRod(p, 4);
	std::cout << "max r:" << r << std::endl;


	//second method
	r = memoryCutRod(p,4);
	std::cout << "max r:" << r << std::endl;


	//third mehod
	r = bottomUpCutRod(p, 4);
	std::cout << "max r:" << r << std::endl;
	return 0;
}


int cutRod(int* p, int n)
{
	if (n == 0)
		return 0;
	int q = INT_FAST32_MIN;
	for (int i = 1; i <= n; i++)
	{
		q = std::max(q, p[i-1] + cutRod(p, n-i));
	}
	return q;
}


int memoryCutRod(int* p, int n)
{
	std::vector<int> r(n + 1, INT_FAST32_MIN);
	return memoryCutRodAux(p, n, r);
}


int memoryCutRodAux(int* p, int n, std::vector<int>& r)
{
	if (r[n] >= 0)
		return r[n];


	int q = INT_FAST32_MIN;
	if (n == 0)
		q = 0;
	else
	{
		for (int i = 1; i <= n; i++)
			q = std::max(q, p[i-1] + memoryCutRodAux(p, n-i, r));
	}
	r[n] = q;
	return q;
}


int bottomUpCutRod(int*p, int n)
{
	std::vector<int> r(n + 1, INT_FAST32_MIN);
	r[0] = 0;
	for (int j = 1; j <= n; j++)
	{
		int q = INT_FAST32_MIN;
		for (int i = 1; i <= j; i++)
		{
			q = std::max(q, p[i-1] + r[j-i]);
		}
		r[j] = q;
	}
	return r[n];
}


5 输出

max r:10
max r:10
max r:10

6 参考

算法导论

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值