动态规划算法思想和分治法的思想是类似的,都是将问题的规模缩小,然后求解子问题,根据子问题来解决总问题,但是分治算法的子问题之间是相互独立的,因此在对子问题的求解过程中就产生了很多重复的计算,递归就是这种问题很典型的代表,究其原因就是对子问题的求解过程没有保留中间结果以便其他的求解问题使用,而动态规划问题将中间结果保留在数组中,每个状态都对应一个状态转移,而且动态规划思想和贪心算法思想也不同,就在于贪心算法是只考虑当前最优解,逐步扩大,从而找到全局最优解,但是这个解通常不是最优解,而是接近与全局最优解,但是动态规划考虑问题是从全局来考虑,每个结果的计算都考虑了当前的最优解,然后逐步扩大,求出全局的最优解,而这个最优解是全局最优解,因为每个解的计算都是从全局来出发的。
1、一维动态规划
求最大子序列的和问题
假设要求的序列是array 0、-2、3、5、1、-2、3 (长度为7)
这个时候设置一个临时数组temp[7],每个temp[i]都是从array[0] 开始到 array[i]的最大子序列的和的值
所以状态转移方程为:temp[i] = max(temp[i-1]+array[i],array[i])
核心思想:
If(temp[i-1]< 0)
Temp[i] = array[i] (因为 temp[i-1] + array[i] < array[i])
Else
Temp[i] = array[i]+temp[i-1];
//实例代码如下
For(i=1;i<len;i++)
{
//处理第一个
Temp[0] = array[0];
If(temp[i-1] < 0)
{
Temp[i] = array[i];
}
Else
{
Temp[i] = temp[i-1]+array[i];
}
If(temp[i] > max)
{
Max = temp[i];
}
}
2、二维动态规划
背包问题(0-1背包问题)
假设有 N 个物体,每个物体的价值为 value[i] (i=0---N-1)每个物体的体积 volumn[i]
现在有一个背包体积为V,求如何放入物体能够使背包的物体价值最大
每个物体都有可能放入或者不放入所以是 0-1问题
设一个二维数组 temp[N][V];
则状态转移方程为
Temp[i][j]= max{
Temp[i-1][j-volumn[i]] + value[i],temp[i-1][j]
}表示第i个物体放入背包和不放人背包
不过需要注意第一个放入背包的物体的情况,因为只有这个物体的体积能够放下的情况下才能放入
//实例代码如下
For(i=0;i<N;i++)
{
For(j=0;j<V;j++)
{
//不是第一个的情况
If(i>0)
{
//放入背包
If(j>= volum[i])
{
Inttp = temp[i-1][j-volumn[i]] + value[i];
If(tp > temp[i][j])
{
Temp[i][j] = tp;
}
Else
{
Temp[i][j] = temp[i][j];
}
}
}
Else
{
If(j >volumn[0])
Temp[0][j] = value[0];
}
}
Return temp[N-1][V-1];
}
/对0-1背包问题的空间优化/
以上0-1背包问题,使用了一个二维数组来进行维护中间值,但是在求解的过程中只是使用到了上一次的计算结果,因此可以使用一个2*V的数组来进行维护,这样空间复杂度就减小到O(K*V)
因此,以上代码的修改为;
//实例代码如下
For(i=0;i<N;i++)
{
For(j=0;j<V;j++)
{
K = i&1;
//不是第一个的情况
If(k > 0)
{
//放入背包
If(j>= volum[i])
{
Inttp = temp[k^1][j-volumn[i]] + value[i];
If(tp > temp[k][j])
{
Temp[k][j] = tp;
}
Else
{
Temp[k][j] = temp[i][j];
}
}
}
Else
{
If(j >volumn[0])
Temp[k^1][j] = value[0];
}
}
Return temp[k][V-1];
}