题目链接

小红的地砖

题目描述

小红要走过一个有 块地砖的场地,地砖从 编号。她从第 块地砖出发,目标是到达第 块地砖。

  • 走到第 块地砖需要消耗 的体力值。
  • 从地砖 ,她可以移动到地砖 (走1步)或地砖 (走2步)。
  • 题目保证
  • 总消耗是所有走过的地砖的体力值之和。

请求出从第 块地砖走到第 块地砖所需消耗的最小体力值。

输入:

  • 第一行一个整数 ,表示地砖数量。
  • 第二行 个整数 ,表示每块地砖的体力消耗。

输出:

  • 一个整数,表示最小体力值。

解题思路

这是一个经典的动态规划问题,与爬楼梯问题类似,但目标是最小化成本而不是计算路径数量。

  1. 定义状态: 我们用 表示到达第 块地砖时,所累积的最小体力消耗。我们的最终目标是求

  2. 状态转移方程: 要到达第 块地砖,我们只可能从第 块或第 块地砖转移而来。

    • 如果从第 块地砖走来:到达 的最小成本是 。踏上第 块地砖后,总成本变为
    • 如果从第 块地砖走来:到达 的最小成本是 。踏上第 块地砖后,总成本变为

    为了使得到达第 块地砖的总成本最小,我们必须选择两者中成本更小的那个来源。因此,状态转移方程为: (其中 是走到第 块地砖的消耗)。

  3. 确定边界条件 (Base Cases):

    • 对于第 1 块地砖 ():我们从这里出发,最小成本就是 。根据题意,,所以
    • 对于第 2 块地砖 ():只能从第 1 块地砖走 1 步到达。所以路径是 ,总成本是 。因此
    • 状态转移方程 适用于
  4. 空间优化: 和斐波那契数列一样,计算 只依赖于前两个状态 。因此,我们可以使用两个变量来滚动保存这两个状态,将空间复杂度从 优化到

代码

#include <iostream>
#include <vector>
#include <algorithm>

using namespace std;

int main() {
    int n;
    cin >> n;
    vector<long long> a(n);
    for (int i = 0; i < n; ++i) {
        cin >> a[i];
    }

    if (n == 1) {
        cout << a[0] << endl;
        return 0;
    }

    long long dp_i_minus_2 = a[0]; // dp[1]
    long long dp_i_minus_1 = a[1]; // dp[2] (注意题目保证 a[0]=0)

    for (int i = 2; i < n; ++i) {
        long long dp_i = min(dp_i_minus_1, dp_i_minus_2) + a[i];
        dp_i_minus_2 = dp_i_minus_1;
        dp_i_minus_1 = dp_i;
    }

    cout << dp_i_minus_1 << endl;

    return 0;
}
import java.util.Scanner;
import java.lang.Math;

public class Main {
    public static void main(String[] args) {
        Scanner sc = new Scanner(System.in);
        int n = sc.nextInt();
        long[] a = new long[n];
        for (int i = 0; i < n; i++) {
            a[i] = sc.nextLong();
        }

        if (n == 1) {
            System.out.println(a[0]);
            return;
        }

        long dp_i_minus_2 = a[0]; // dp[1]
        long dp_i_minus_1 = a[1]; // dp[2] (注意题目保证 a[0]=0)

        for (int i = 2; i < n; i++) {
            long dp_i = Math.min(dp_i_minus_1, dp_i_minus_2) + a[i];
            dp_i_minus_2 = dp_i_minus_1;
            dp_i_minus_1 = dp_i;
        }

        System.out.println(dp_i_minus_1);
    }
}
n = int(input())
a = list(map(int, input().split()))

if n == 1:
    print(a[0])
else:
    # dp_i_minus_2 对应 dp[i-2] 的值, 初始化为 dp[1] 的成本
    # dp_i_minus_1 对应 dp[i-1] 的值, 初始化为 dp[2] 的成本
    dp_i_minus_2 = a[0]
    dp_i_minus_1 = a[1]

    # 从第3块地砖开始循环
    for i in range(2, n):
        # 计算到达当前地砖 i+1 的最小成本
        dp_i = min(dp_i_minus_1, dp_i_minus_2) + a[i]
        # 更新滚动变量
        dp_i_minus_2 = dp_i_minus_1
        dp_i_minus_1 = dp_i

    print(dp_i_minus_1)

算法及复杂度

  • 算法:动态规划(滚动数组优化)
  • 时间复杂度: - 我们需要遍历一次地砖数组来计算最小成本。
  • 空间复杂度: - 主要用于存储输入的 个体力值。DP计算本身的空间是