DP-动态规划

动态规划

1 动态规划(DP)是什么?

动态规划是一种解决问题的思想。动态规划最关键的问题在于找到子问题模型。

(1) DP的自顶向下思想。

比如递归,递归会不停的调用同一段代码,自顶而下,类似于树结构,当然,结果还是依赖出口,再层层由下层返回到上层。但是我们说,这种解决问题的思想就是DP的自顶向下思想。

(2) DP的自下而上思想。

比如迭代,for循环。这个子问题的结果作为下一个子问题的初始条件,直到计算出最终结果。这种由小到大的就是DP的自下而上思想。

(3) DP的状态转移方程。

找到子问题,再将子问题抽象为数学公式,这个公式就是状态转移方程。

(4)DP优化问题。

一般来讲找到状态转移方程以后,同样的问题,利用DP思想就有两种解法,一种是自顶而上的解法,一种就是自下而上的解法。这两种解法无论是哪一种,在解决子问题的时候都会出现重复子问题的现象。因此,可以做一个缓存,从而降低时间复杂度。

二 例子

1 斐波那契问题

公式

(1 )FB(n)=FB(n-1)+FB(n-2);n>2
(2)F(n)=1;n==1 || n==2

调用代码:

  int r= FB2(7);
    printf("%d \n",r);

DP自顶向下如下解:

int FB(int n){
    if (n==1 || n==2) {
        return 1;
    }
    return FB(n-1)+FB(n-2);
}

DP自下而上如下解:

//动态规划
int FB1(int n){
    if (n==1 || n==2) {
        return 1;
    }
    
    //创建一维数组缓存结果。
    int arr[n+1];
    memset(arr, n, sizeof(int)*(n+1));
    
    arr[0]=arr[1]=1;
    
    for (int i=2; i<n; i++) {
        arr[i]=arr[i-1]+arr[i-2];
    }
    return arr[n-1];
}

DP自下而上如下解优化

//动态规划优化
int FB2(int n){
    if (n==1 || n==2) {
        return 1;
    }
    

    int a=1,b=1;
    int c=0;
    
    for (int i=2; i<n; i++) {
        c=a+b;
        a=b;
        b=c;
    }
    return c;
}

空间复杂度最终被优化为O(1);

0-1背包问题
我们有n种物品,物品j的重量为wj,价格为pj。
我们假定所有物品的重量和价格都是非负的。背包所能承受的最大重量为W。
如果限定每种物品只能选择0个或1个,则问题称为0-1背包问题 。

子问题分析->状态转移方程。
1 如果一件物品放入背包,超过了剩余空间。那么 max = bagValues(index - 1, limitWeight);
2 // 如果选择此时的重量最大值
int selectValue = curValue + bagValues(index - 1, limitWeight - curWeight);
// 如果跳过此时的重量最大值
int skipValue = bagValues(index - 1, limitWeight);
max = MAX(selectValue, skipValue);

3 代码实现

/**
 输入:
     int Values[n] 物品的价值
     int Weights[n] 物品的重量
     int LimitWeight 背包容量剩余大小
 输出:
    MaxValue 背包里的物品最大价值
 
 状态:取:最大价值(取)/不是最大价值(取过之后)
      不取:重量超出限制
      物品重量不得超过最大重量限制
 */
int *values;
int *weights;
int bagValues(int index, int limitWeight) {
    if(limitWeight <= 0 || index < 0 ){
       return 0;
    }
    int max = 0;
    // 当前物品重量
    int curWeight = weights[index];
    // 当前物品价值
    int curValue = values[index];
    if (curWeight > limitWeight) {
        // 超过重量限制,跳过
        max = bagValues(index - 1, limitWeight);
    } else {
        // 如果选择此时的重量最大值
        int selectValue = curValue +  bagValues(index - 1, limitWeight - curWeight);
        // 如果跳过此时的重量最大值
        int skipValue = bagValues(index - 1, limitWeight);
        max = MAX(selectValue, skipValue);
    }
   return  max;
}

调用部分:

int main(int argc, const char * argv[]) {
    int vs[] = {4, 10, 17};
    int ws[] = {1, 2, 3};
    values = vs;
    weights = ws;
    
    int m = bagValues(1, 5);
    
    printf("%d \n",m);
    return 0;
}

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

肉丸饭团

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值