使用 C 语言动态规划法解决最大硬币总和问题:逐行代码解释

**问题描述:**现有 n 个硬币按顺序依次排列在你面前,它们的面值可以看作一个数组 coins[] = {5, 1, 2, 10, 6, 2},请在此中选取若干个硬币,使得所取硬币面值总和最大,捡取个数不限,但相邻的硬币不能捡取。请设计动态规划算法,要求能够输出累加值和选取的硬币序号(硬币面值为正数)。

**a. 问题分析:**给定一个硬币数组,要求选取若干个硬币,使得所取硬币面值总和最大,但相邻的硬币不能被选取。

**b. 解题思路:**使用动态规划思想,创建一个大小为 n+1 的数组 dpdp[i] 表示前 i 个硬币能取得的最大面值总和。递推公式为:dp[i] = max(dp[i-1], dp[i-2]+coins[i-1]),其中 dp[i-1] 表示不选取第 i 个硬币,dp[i-2]+coins[i-1] 表示选取第 i 个硬币。最终返回 dp[n] 即为所求。

c. 代码实现如下:

#include <stdio.h>

int maxCoinValue(int coins[], int n, int *coinIndex) {
    int dp[n+1]; // 创建一个大小为 n+1 的数组 dp
    dp[0] = 0; // 初始化 dp[0] 为 0
    dp[1] = coins[0]; // 初始化 dp[1] 为第一个硬币的面值

    // 逐个计算 dp[i]
    for (int i = 2; i <= n; i++) {
        // 不选取第 i 个硬币,dp[i] 等于前一个硬币的面值总和
        int value1 = dp[i-1];
        // 选取第 i 个硬币,dp[i] 等于前两个硬币的面值总和加上第 i 个硬币的面值
        int value2 = dp[i-2] + coins[i-1];
        // 取两者中的最大值
        dp[i] = (value1 > value2) ? value1 : value2;
    }

    // 回溯选取的硬币
    *coinIndex = n; // 从最后一个硬币开始回溯
    int sum = dp[n]; // 最大面值总和
    while (*coinIndex >= 1) {
        // 如果选取了第 *coinIndex 个硬币,则继续回溯到第 *coinIndex-2 个硬币
        if (dp[*coinIndex] == dp[*coinIndex-2] + coins[*coinIndex-1]) {
            *coinIndex -= 2;
        }
        // 否则继续回溯到第 *coinIndex-1 个硬币
        else {
            *coinIndex -= 1;
        }
    }

    return sum; // 返回最大面值总和
}

int main() {
    int coins[] = {5, 1, 2, 10, 6, 2};
    int n = sizeof(coins) / sizeof(coins[0]);
    int coinIndex = 0;
    int sum = maxCoinValue(coins, n, &coinIndex);

    printf("最大面值总和为:%d\n", sum);
    printf("选取的硬币序号为:");
    for (int i = coinIndex; i < n; i++) {
        printf("%d ", i+1);
    }
    printf("\n");

    return 0;
}

代码注释中解释了每一行代码的作用,包括动态规划的递推公式和回溯选取的硬币。最终输出最大面值总和和选取的硬币序号。

C语言动态规划法解决最大硬币总和问题:逐行代码解释

原文地址: https://www.cveoy.top/t/topic/pfWH 著作权归作者所有。请勿转载和采集!

免费AI点我,无需注册和登录