动态规划

动态规划与分支方法相似,都是通过组合子问题的解求解原问题
其步骤分为:
(1):刻画一个最优解的结构特征。
(2):递归地定义最优解的值。
(3):计算最优解的值,通常采取自底向上的方法。
(4):利用计算出的信息构造一个最优解。
## 钢条切割问题 ##

这里写图片描述

CUT-ROD(int *p,n)
if(n==0)
return 0;
int q=-INF;//作为标记
for(int i=1;i<=n;i++)
{
int q=max(q,p[i]+CUT-ROD(p,n-i));
}
return q;

过程CUT-ROD以价格数组p[1…n]和整数n作为输入,返回长度为n的钢条的最大收益,若N=0,不可能有任何收益,所以返回0,
然后将最大收益初始化为负无穷,下面就是计算结果。。运用递归的思想。

## 带备忘的自顶向下法 ##
此方法按照自然的递归形式编写过程,但过程会保存每个子问题的解。当需要一个子问题的解时,过程首先检查是否已保存过此解。如果是,则直接返回保存的值,从而节省了计算时间,否则按照通常的方式计算这个问题.所以我们称这个递归过程是带备忘的,因为他记住了之前已经计算出的结果。
MEMORIZD-CUT-ROD(int *p,int n)
{
int r[n];
for(int i=0;i<n;i++)
{
r[i]=-INF;
}
return MEMORIZED-CUT-ROD-AUX(p,n,r);
}
MEMORIZED-CUT-ROD-AUX(int *p,int n,int *r)
{
if(r[n]>=0)
    {
        return r[n];
    }
if(n==0)
    int q=0;
else
{
    int q=-INF;
    for(int i=1;i<n;i++)
        {
            q=max(q,p[i]+MEMORIZED-CUT-ROD-AUX(p,n-i,r));
        }
}
    r[n]=q;
    return q;
}

伪代码解释
这里写图片描述

## 自底向上版本 ##
BOTTOM-UP-CUT-ROD(int *p,int n)
{
int r[n]//new array
r[0]=0;
for(int j=0;j<n;j++)
{
    int q=-INF;
    for(int i=1;i<=j;i++)
    {
    q=max(q,p[i]+r[j-i])
    }
r[j]=q;
}
return r[n];
}
## 伪代码解释(自底向上) ##

创建一个新数组r[]来保存子问题的解,将其第一个元素初始化为0;因为长度为0的钢条没有收益。接下来,解释按照升序求解每个规模为J的子问题,方法同上,只是现在直接访问数组元素r[j-i]来获得规模为j-i的子问题的解,而不必进行递归调用,然后将规模为J的子问题存入r[j]。最后返回r[n],即最优解r_n;

## 重构解 ##

前文给出的钢条切割问题的动态规划返回最优解的收益值,但并未返回解本身,我们可以扩展动态规划算法,使之对每个子问题不仅保存最优收益值,还能保存对应的切割方案
于是下面代码的作用是得到最大收益值,还能得到对应的第一段钢条的切割产长度。

EXTENDED-BOTTOM-UP-DUT-ROD(int *p,int n)
{
int r[n];
int s[n];
r[0]=0;
for(int j=1;j<n;j++)
 {
q=-INF;
for(int i=1;i<j;i++)
{
 if(q<p[i]+r[j-i])
   {
  q=p[i]+r[j-i];
  s[j]=i;
   }
}
 r[j]=q;
 }
 return r && s;
}

下面的过程接受两个参数:价格表P和钢条长度N然后调用上面的函数来计算切割下来的每段钢条的长度S[1…N],然后输出长度为N的钢条的完整的最优切割方案:

PEINT-CUT-ROD-SOLUTION(int *p,int n)
{
(r,s)=EXTENDED-BOTTOM-UP-CUT-ROD(p, n);
while(n>0)
{
printf s[n];
n=n-s[n];
}
}

程序结果:
这里写图片描述

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值