小偷与守望者.math库.动态规划.贪心.C

1.分别讨论0或1;边界

2.写出递推方程;最优子结构、状态转移方程、重叠子问题

int rob(int* arr, int size){

    int dp[size];int result;

    if(size==0)return 0;

    if(size==1)return arr[0];

    else{

        dp[0]=arr[0];

        dp[1]=arr[1] > arr[0] ? arr[1]:arr[0];

        for (int i = 2; i < size; ++i) {

            dp[i]= dp[i-1]>arr[i]+dp[i-2] ? dp[i-1]:arr[i]+dp[i-2]; //注意arr 和 dp ;dp进入下一次递推

        }

        result=dp[size-1];

        return  result;

 低空间写法:

滚轮数组

int rob(int* nums, int numsSize) {
    int retVal = 0;

    if (numsSize == 0) {
        return retVal;
    } else if (numsSize == 1) {
        return nums[0];
    }

    int first = nums[0];
    int second = fmax(nums[0], nums[1]);
    int temp;
    int i;
    for (i = 2; i < numsSize; ++i) {
        temp = second;
        second = fmax(first + nums[i], second);
        first = temp;
    }
    retVal = second;

    return retVal;
}

 遍历修减

int rob(int* nums, int numsSize){
    if (numsSize == 1) {
        return *nums;
    }

    nums[1] = fmax(nums[0], nums[1]);
    for (int i = 2; i < numsSize; i++) {
        nums[i] = fmax(nums[i - 2] + nums[i], nums[i - 1]);
    }

    return fmax(nums[numsSize - 1], nums[numsSize - 2]);
}

函数fmax(x,y) 返回较大值;


自底向上的动态规划:

在青蛙跳阶问题中:一只青蛙一次可以跳上1级台阶,也可以跳上2级台阶。求该青蛙跳上一个 10 级的台阶总共有多少种跳法。

  • f(n-1)和f(n-2) 称为 f(n)  最优子结构
  • f(n)= f(n-1)+f(n-2)状态转移方程
  • f(1) = 1, f(2) = 2 边界
  • 比如f(10)= f(9)+f(8),f(9) = f(8) + f(7) ,f(8) 重叠子问题

 for循环从f(1)到f(10)即可;

1. 穷举分析

  • 当台阶数是1的时候,有一种跳法,f(1) =1
  • 当只有2级台阶时,有两种跳法,第一种是直接跳两级,第二种是先跳一级,然后再跳一级。即f(2) = 2;
  • 当台阶是3级时,想跳到第3级台阶,要么是先跳到第2级,然后再跳1级台阶上去,要么是先跳到第 1级,然后一次迈 2 级台阶上去。所以f(3) = f(2) + f(1) =3

2. 确定边界

通过穷举分析,我们发现,当台阶数是1的时候或者2的时候,可以明确知道青蛙跳法。f(1) =1,f(2) = 2

3. 找规律,确定最优子结构,写转移方程和code

int frogJump(int n){
    if(n<0)return -1;
    int li[n+1];
    li[0]=0;
    li[1]=1;
    li[2]=2;
    for (int i = 3; i <= n; ++i)
        li[i]=li[i-1]+li[i-2];
    return li[n];
}

一道动态规划问题,其实就是一个递推问题。假设当前决策结果是f(n),则最优子结构就是要让 f(n-k) 最优,最优子结构性质就是能让转移到n的状态是最优的,并且与后面的决策没有关系,即让后面的决策安心地使用前面的局部最优解的一种性质



 贪心

找局部最优:

int main() {
    long long m, s, t, i = 1;
    long long blink = 0, sum = 0;
    scanf("%lld %lld %lld", &m, &s, &t);
    while (i <= t) {
        sum = sum + 17;
        if (m >= 10) {
            blink = blink + 60;
            m = m - 10;
        } else
            m = m + 4;
        
        sum = fmax(sum, blink);
        if (s <= sum) {
            printf("Yes\n%lld", i);
            break;
        }
        i++;
    }
    if (i > t) {
        printf("No\n");
        printf("%d\n", sum);
    }
    return 0;
}

  • 建立数学模型来描述问题
  • 把求解的问题分成若干个子问题
  • 对每个子问题求解,得到子问题的局部最优解
  • 把子问题的解局部最优解合成原来问题的一个解

 前提是:局部最优策略能导致产生全局最优解。

贪心算法的实现框架


从问题的某一初始解出发:
while (朝给定总目标前进一步)
{
利用可行的决策,求出可行解的一个解元素。
}
由所有解元素组合成问题的一个可行解;

【背包问题】有一个背包,容量是M=150,有7个物品,物品可以分割成任意大小。要求尽可能让装入背包中的物品总价值最大,但不能超过总容量。
物品:A B C D E F G
重量:35 30 60 50 40 10 25
价值:10 40 30 50 35 40 30
分析:
目标函数: ∑pi最大
约束条件是装入的物品总质量不超过背包容量:∑wi<=M( M=150)
(1)根据贪心的策略,每次挑选价值最大的物品装入背包,得到的结果是否最优?
(2)每次挑选所占重量最小的物品装入是否能得到最优解?
(3)每次选取单位重量价值最大的物品,成为解本题的策略


 动态规划的设计,其实就是利用最优子结构和重叠子问题性质对穷举法进行优化,通过将中间结果保存在数组中,实现用空间来换取时间交换,实现程序的快速运行。(动态规划求解时,一般都会转化为网格进行求解,而且因为是空间换时间(避免了子问题的重复计算),因此一般迭代求解)。

动态规划具有两个性质:

1)重叠子问题

2)最优子结构

贪心算法:

1)贪心选择性质

2)最优子结构

解释一下,最优子结构性质是指问题的最优解包含其子问题的最优解时,就称该问题具有最优子结构性质,重叠子问题指的是子问题可能被多次用到,多次计算,动态规划就是为了消除其重叠子问题而设计的。其实贪心算法是一种特殊的动态规划,由于其具有贪心选择性质,保证了子问题只会被计算一次,不会被多次计算,因此贪心算法其实是最简单的动态规划。

考虑最值解,状态小规模问题的数学表示,状态转移方程(大规模问题如何转化为更小的问题),返回值

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值