东华大学oj-贪心算法

最近学到动态规划,把写的代码题分享一下。

动态规划顾名思义,就是在处理任务的时候,任务的脉络不是预先被完全预料好的,需要在运算中

一步步推算的。

这么说可能很难理解它的特殊性我来举几个例子。

最著名的就是我们的青蛙跳台阶问题。(青蛙一次跳一或两阶,跳n阶有多少种跳法)

有的同学可能就开始混淆了,明明这个是经典的递归问题,类似斐波那契数列,怎么会扯上动态规划呢?

我们先看看一般解法:(递归)

逻辑大概是这样的,青蛙在跳第到n阶的时候,它可能是从n-1阶跳一阶上来的,也有可能是从n-2阶跳上来的。这样就将问题简单化。

接着进行递归,结束条件是n=1/2(负数几乎不可能)

代码如下:

public class FrogJump {

    public static int jumpWays(int n) {
        if (n <= 0) {
            return 0;
        }
        if (n == 1) {
            return 1;
        }
        if (n == 2) {
            return 2;
        }
        
        // 当前台阶可以选择跳1级或者2级
        return jumpWays(n - 1) + jumpWays(n - 2);
    }

    public static void main(String[] args) {
        int n = 5; // 台阶数
        int ways = jumpWays(n);
        System.out.println("跳上 " + n + " 级台阶的方法数为:" + ways);
    }
}

那么动态规划如何解这个递归问题呢?

很有意思吧,结构出奇的一致,却有些不同

public class FrogJump {

    public static int jumpWaysDP(int n) {
        if (n <= 0) {
            return 0;
        }
        if (n == 1) {
            return 1;
        }
        if (n == 2) {
            return 2;
        }
        
        int[] dp = new int[n+1];
        dp[1] = 1;
        dp[2] = 2;
        
        for (int i = 3; i <= n; i++) {
            dp[i] = dp[i - 1] + dp[i - 2];
        }
        
        return dp[n];
    }

    public static void main(String[] args) {
        int n = 5; // 台阶数
        int ways = jumpWaysDP(n);
        System.out.println("跳上 " + n + " 级台阶的方法数为:" + ways);
    }
}

你看这个代码是将每一阶的跳法存储在一个数组中,然后再对数组的数进行处理,这里的逻辑是相加。这就成了一个动态规划的代码。

接着我们来看问题:

问题很有意思,有顺序的一组数(并没有经过排序)给到你,你不可以选相邻的,最后选出满足和最大的所有数。(只需要和)

这个问题复杂起来了,因为0并不是选取最大的数就行,你得考虑到你前面选定的数可能在一个特殊的时候需要推倒从来,我给你一个例子。

给你一个例子。

1,2,3,4,1000,5这个数组。

你从前往后看,1和2比较明显2大,因此我选择2;

选择2后往后走发现出现比2更大的3,因此选择3.现在我们不能忘记1,它也可以被装进来。

接下来是4,如果选择4的话明显4+2>1+3,因此抛弃1,3选择2,4.

接着是1000这个数,1000+1+3>2+4+5。因此选择1,3,1000.

接着到5,1+3+1000>2+4+5.

结果是什么1+3+1000.

我们来看这个计算的过程,发现明显是怎么样的?

明显是冗杂的,动态的,符合我们之前讲的动态规划,我们来应用一下。

利用数组来存储每一步选择后的情况,比如说1+3,2+4明显应用了多次,我们大可以用数组进行储存,后面来了新数进行比较。

怎么比较呢,例如来了个新数字x,和挨着的上次的和进行比较。多说无益,我们来看代码

import java.util.Scanner;

public class oj1 {

    public static void main(String[] args) {
        Scanner scanner = new Scanner(System.in);

        int n = scanner.nextInt();
        int[] values = new int[n]; // 例子数组

        for (int i = 0; i < n; i++) {
            values[i] = scanner.nextInt();
        }

        int[] dp = new int[n]; // 创建一个数组用于存储最大值

        // 初始化动态规划数组
        dp[0] = values[0];
        if (n > 1) {
            dp[1] = Math.max(values[0], values[1]);
        }

        // 动态规划求解
        for (int i = 2; i < n; i++) {
            dp[i] = Math.max(dp[i - 1], dp[i - 2] + values[i]);
        }

        // 打印最大总值
        System.out.println(  dp[n - 1]);

        scanner.close(); // 关闭 Scanner 对象
    }
}

你要知道下一个最大和就是max(前一个最大和,前前一次最大和+当前值)

 很有意思吧,这么简单的代码循环起来就不一样,多去试试,这里的关键就是你之前求得最大和并不会改变了。

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值