算法学习(二)——动态规划初步

这篇博客介绍了动态规划的基础,通过斐波那契数列问题阐述动态规划的核心思想,避免重复计算子问题。接着讨论了PowerOJ 1027题目——买花瓶问题,解释如何应用简单动态规划DP解决这个问题,旨在帮助读者理解动态规划的实战应用。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

算法学习(二)——动态规划初步

参考:
算法-动态规划 Dynamic Programming–从菜鸟到老鸟
动态规划(Dynamic Programming)基础

## 前言 在刚上大一的时候,刚接触C语言的我,竟然有着一颗ACMer的梦,当然,最后磨灭了。记得当时一个ACM的学长给我说,让我先把动态规划学习了……呃,这么久了,还是第一次看动态规划。当然,现在还是看到最简单的动态规划。 ## 核心 首先说动态规划算法的核心吧,这也是我看完大神的博客以后并且知道什么是动态规划之后了解到的第一个知识: 首先是一个小例子 >A “1+1+1+1+1+1+1+1 =?” A : “上面等式的值是多少” B : 计算 “8!” A 在上面等式的左边写上 “1+” A : “此时等式的值为多少” B : quickly “9!” A : “你怎么这么快就知道答案了” A : “只要在8的基础上加1就行了” A : “所以你不用重新计算因为你记住了第一个等式的值为8!动态规划算法也可以说是 ‘记住求过的解来节省时间’”

这个小例子其实已经可以阐述动态规划的核心了:记住已经解决过的子问题的解

小例题:斐契那波数列问题

相信大家都知道美国电影里的FBI,可是大家是否知道意大利数学家斐波那契提出的著名的FIB数列呢,其定义如下:对于正整数数列A[n]有
A [ 1 ] = 1 , A [ 2 ] = 1 , A [ N ] = A [ N − 1 ] + A [ N − 2 ] ( N > 2 ) A[1] = 1, A[2] = 1, A[N] = A[N-1] + A[N-2] (N>2) A[1]=1,A[2]=1,A[N]=A[N1]+A[N2](N>2)
现在你的任务是求出Fibonacci数列的第n项。

这个题我记得是刚学数组的时候的一道练习题,当然,这个题用递归其实就是几行代码的事情,超级简单,但是今天我们要来看看递归和简单DP的差距。

/*递归算法*/
public static int recursionFibonacci(int n){
    if(n==0)
        return 0;
    if(n==1)
        return 1;
    return recursionFibonacci(n-1)+recursionFibonacci(n-2);
}

借用一下大佬博客上面的图,我们来看看用简单递归来求这个数列的算法效率。
Alt text
这里可以看到,假如我们输入6,然后这是使用简单递归算法的步骤,可以看到,光是fib(2)就执行了5次,这不就很浪费时间了。
下面我们看看使用动态规划的算法:

//自顶向下的备忘录法
public static int Fibonacci(int n)
{
    if(n<=0)
        return n;
    int []Memo=new int[n+1];        
    for(int i=0;i<=n;i++)
        Memo[i]=-1;
    return fib(n, Memo);
}
public static int fib(int n,int []Memo)
{

    if(Memo[n]!=-1)
        return Memo[n];
//如果已经求出了fib(n)的值直接返回,否则将求出的值保存在Memo备忘录中。               
    if(n<=2)
        Memo[n]=1;

    else Memo[n]=fib( n-1,Memo)+fib(n-2,Memo);  

    return Memo[n];
}
//自底向上的动态规划
public static int fib(int n)
{
    if(n<=0)
        return n;
    int []Memo=new int[n+1];
    Memo[0]=0;
    Memo[1]=1;
    for(int i=2;i<=n;i++)
    {
        Memo[i]=Memo[i-1]+Memo[i-2];
    }       
    return Memo[n];
}

这里展示了两种动态规划的算法示例,代码不一一赘述,只要记住动态规划的核心是记住已经解决的子问题的过程然后再看代码就一目了然了。

实操

PowerOJ 1027:买花瓶(简单动态规划DP)

Description

john想买几个花瓶装饰一下新房。已知花店的花瓶被固定地排成一行并被依次排号,且花店有
一个原则,花瓶不能移动也不能挑选,只能买连号的花瓶。由于每个花瓶都有自己的美学价值,
请你帮john选出其中美学价值最大的一组。
比如,有六个花瓶,它们的美学价值分别是 3 -1 2 4 -6 5,那么john应该选3 -1 2 4(美学价值为8)
这一组。而不能挑2 3 4 5这一组(违犯),或是2 4组(美学价值为6,不是最大)。

Input

测试有很多次,对于每一次测试:
第一行为一个正整数 N( 1 <= N <=10000 ),代表花瓶的个数.当N=0时,代表测试结束;
第二行的N个整数Mi( -100 <= Mi <= 100 )分别代表每个花瓶的美学价值,其间用空格分开。

output

每次测试输出一行,代表拥有最大美学价值的一组连号花瓶的美学价值MAX。

Sample Input

6
3 -1 2 4 -6 5
0

Sample Output

6

解题

public static int maxAC(int array[],int n){
   int result=array[0];//保存最大值
   for (int i=1;i<n;i++){
        if (array[i-1]>0){
            array[i]=array[i-1]+array[i];
        } else {
            array[i]=array[i];
        }
    }
    for (int i=1;i<n;i++){
        if (array[i]>result)
            result=array[i];
    }
    return result;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值