返回

智慧解题,一招制胜 - 贪吃猴子的命运抉择

前端

贪吃猴子的智慧盛宴:两种算法,一招制胜

算法的魅力,解题的乐趣

对于算法爱好者而言,解决一道精彩的算法题,无异于一场智力盛宴。华为OD机试中的“贪吃的猴子”题目就是一道经典难题,吸引了许多程序员跃跃欲试。该题要求我们设计一个算法,帮助贪吃猴子在最短的时间内获取最多的水果。

算法选择:两种思路,各显神通

要解决“贪吃的猴子”问题,我们可以采用两种主要算法:动态规划和贪心算法。

动态规划:步步为营,最优解累积

动态规划是一种强大的算法,它将复杂问题分解为一系列较小的子问题,并通过逐步解决这些子问题来求解原始问题。在“贪吃的猴子”中,我们可以将整个过程分解为一系列子问题,每个子问题对应于猴子当前所处的位置和剩余的时间。通过动态规划,我们可以计算出在每个子问题中的最优解,并逐步累加这些最优解,最终得到原始问题的最优解。

贪心算法:快速决策,未必完美

贪心算法是一种更为直观的算法,它总是选择当前看来最优的方案,而不考虑未来可能存在更好的方案。在“贪吃的猴子”中,贪心算法会选择猴子当前能够获得最多的水果的路径,并以此作为前进的方向。虽然贪心算法不能保证总是找到最优解,但它通常能够在较短的时间内找到一个足够好的解。

代码实现:Java、Python、C++、C

掌握了算法原理,下面我们来看看如何用代码实现这些算法。

Java实现:

//动态规划法
import java.util.Scanner;

public class GreedyMonkeyDP {

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

        // 获取输入
        int n = sc.nextInt();  // 树的层数
        int m = sc.nextInt();  // 猴子可移动的步数
        int[] trees = new int[n];  // 每棵树上的水果数量

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

        // 初始化动态规划表
        int[][] dp = new int[n][m + 1];

        // 填写动态规划表
        for (int i = 0; i < n; i++) {
            for (int j = 1; j <= m; j++) {
                if (i == 0) {
                    dp[i][j] = trees[i];
                } else {
                    dp[i][j] = Math.max(dp[i - 1][j - 1] + trees[i], dp[i - 1][j]);
                }
            }
        }

        // 输出结果
        System.out.println(dp[n - 1][m]);
    }
}

//贪心算法
import java.util.Scanner;

public class GreedyMonkey {

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

        // 获取输入
        int n = sc.nextInt();  // 树的层数
        int m = sc.nextInt();  // 猴子可移动的步数
        int[] trees = new int[n];  // 每棵树上的水果数量

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

        // 初始化贪心算法
        int maxFruits = 0;
        int currentTree = 0;
        int remainingSteps = m;

        // 循环移动猴子
        while (remainingSteps > 0 && currentTree < n) {
            // 选择当前能获得最多水果的树
            int maxFruitTree = currentTree;
            for (int i = currentTree + 1; i <= currentTree + remainingSteps && i < n; i++) {
                if (trees[i] > trees[maxFruitTree]) {
                    maxFruitTree = i;
                }
            }

            // 移动猴子并收集水果
            maxFruits += trees[maxFruitTree];
            currentTree = maxFruitTree;
            remainingSteps -= (currentTree - currentTree);
        }

        // 输出结果
        System.out.println(maxFruits);
    }
}

Python实现:

#动态规划法
def greedy_monkey_dp(n, m, trees):
    # 初始化动态规划表
    dp = [[0] * (m + 1) for _ in range(n)]

    # 填写动态规划表
    for i in range(n):
        for j in range(1, m + 1):
            if i == 0:
                dp[i][j] = trees[i]
            else:
                dp[i][j] = max(dp[i - 1][j - 1] + trees[i], dp[i - 1][j])

    # 返回结果
    return dp[n - 1][m]

#贪心算法
def greedy_monkey(n, m, trees):
    # 初始化贪心算法
    max_fruits = 0
    current_tree = 0
    remaining_steps = m

    # 循环移动猴子
    while remaining_steps > 0 and current_tree < n:
        # 选择当前能获得最多水果的树
        max_fruit_tree = current_tree
        for i in range(current_tree + 1, current_tree + remaining_steps + 1):
            if i < n and trees[i] > trees[max_fruit_tree]:
                max_fruit_tree = i

        # 移动猴子并收集水果
        max_fruits += trees[max_fruit_tree]
        current_tree = max_fruit_tree
        remaining_steps -= (current_tree - current_tree)

    # 返回结果
    return max_fruits

C++实现:

//动态规划法
#include <iostream>
#include <vector>

using namespace std;

int greedy_monkey_dp(int n, int m, vector<int>& trees) {
    // 初始化动态规划表
    vector<vector<int>> dp(n, vector<int>(m + 1, 0));

    // 填写动态规划表
    for (int i = 0; i < n; i++) {
        for (int j = 1; j <= m; j++) {
            if (i == 0) {
                dp[i][j] = trees[i];
            } else {
                dp[i][j] = max(dp[i - 1][j - 1] + trees[i], dp[i - 1][j]);
            }
        }
    }

    // 返回结果
    return dp[n - 1][m];
}

//贪心算法
int greedy_monkey(int n, int m, vector<int>& trees) {
    // 初始化贪心算法
    int max_fruits = 0;
    int current_tree = 0;
    int remaining_steps = m;

    // 循环移动猴子
    while (remaining_steps > 0 && current_tree < n) {
        // 选择当前能获得最多水果的树
        int max_fruit_tree = current_tree;
        for (int i = current_tree + 1; i <= current_tree + remaining_steps && i < n; i++) {
            if (trees[i] > trees[max_fruit_tree]) {
                max_fruit_tree = i;
            }
        }

        // 移动猴子并收集水果
        max_fruits += trees[max_fruit_tree];
        current_tree = max_fruit_tree;
        remaining_steps -= (current_tree - current_tree);
    }

    // 返回结果
    return max_fruits;
}

C实现:

//动态规划法
#include <stdio.h>
#include <stdlib.h>

int greedy_monkey_dp(int n, int m, int trees[]) {
    // 初始化动态规划表
    int dp[n][m + 1];
    for (int i = 0; i < n; i++) {
        for (int j = 0; j <= m; j++) {
            dp[i][j] = 0;
        }
    }

    // 填写动态规划表
    for (int i = 0; i < n; i++) {
        for (int j = 1; j <= m; j++) {
            if (i == 0) {
                dp[i][j] = trees[i];
            } else {
                dp[i][j] = fmax(dp