【备战秋招】每日一题:2023.2.22-拼多多OD机试-爬山

该问题描述了一个登山者在不同高度台阶上寻找不同爬山方案的场景,利用动态规划方法解决。输入包括山的数量、最大爬升高度和最大跨越步数,以及每个山的具体台阶高度。对于每个山,计算满足条件的爬山方案数。当台阶高度超过最大爬升高度时,方案数为0。提供的代码示例展示了C++、Python、Java和JavaScript的解决方案。
摘要由CSDN通过智能技术生成

为了更好的阅读体检,可以查看我的算法学习博客
在线评测链接:P1045

题目内容

塔子哥是一个热爱户外运动的人,他周末经常约朋友一起登山。华光林山清水秀,景色宜人,让他感到非常愉悦。他喜欢在登山的过程中欣赏美景,感受大自然的魅力。同时,他也喜欢挑战自己,尝试攀登更高的山峰。

塔子哥登山时每一步可以选择向上爬一个台阶或者多个台阶,如果登山时选择的台阶不同,则为一种爬山方案。

塔子哥想知道,华光林的每座山各有多少种不同的爬山方案(输出结果对 10^9 +7 取模)。

输入描述

第一行,三个整数 N N N P P P K K K 分别代表山的个数 N N N ,塔子哥一次最高能爬的高度 P P P 以及塔子哥一次最多能跨越的台阶数 K K K

( 1 ≤ N ≤ 10 , 1 ≤ P ≤ 1 , 000 , 1 ≤ K ≤ 1 , 000 ) ( 1 \le N \le 10 , 1 \le P\le 1,000 , 1 \le K \le 1,000 ) (1N101P1,0001K1,000)

接下来 N N N 行,每行的第一个整数 M i M_i Mi 表示第 i i i 座山一共有 M i M_i Mi 个台阶,接下来有 M i M_i Mi 个整数,分别表示每个台阶的高度 H j H_j Hj

( 1 ≤ M i ≤ 10 , 000 , 1 ≤ H j ≤ 1 , 000 ) ( 1 \le M_i \le 10,000, 1\le H_j \le 1,000 ) (1Mi10,000,1Hj1,000)

输出描述

输出 N N N 行,每行一个整数,表示第 i i i 座山塔子哥可以选择的登山方案数目。

样例

输入

3 3 2
4 1 1 1 1
4 2 2 2 2
5 2 2 2 3 4

输出

5
1
0

备注

如果某一台阶 H j H_j Hj 的高度超过了塔子哥次能爬的高度 P P P , 那塔子哥就不会选择这爬座山, 登山方案数为 0 0 0

思路:线性DP

本题是斐波那契问题的变种,普通的爬楼梯问题中,每个台阶的高度都为 1 1 1,且一次要么向上爬一个台阶,要么向上爬两个台阶。

本题第 i i i 个台阶高度为 h i h_i hi ,一次最高能爬 P P P 的高度,一次最多能爬 K K K 个台阶。

定义 d p [ i ] dp[i] dp[i] 表示爬了 [ 1 , i ] [1, i] [1,i] i i i 个楼梯的方案数,则考虑从 j ∈ [ 0 , i − 1 ] j \in [0, i-1] j[0,i1] i i i 种楼梯开始爬一次,到达 i i i 的总方案数。

这需要满足 i − j ≤ K , h i + h i − 1 + ⋯ + h j + 1 ≤ P i-j\leq K, h_i+h_{i-1}+\cdots+h_{j+1}\leq P ijK,hi+hi1++hj+1P
在满足这种条件的 j j j 下, d p [ i ] = ∑ d p [ j ] dp[i] = \sum\limits {dp[j]} dp[i]=dp[j]

类似题目推荐

LeetCode

  1. 509. 斐波那契数
  2. 70. 爬楼梯
  3. 746. 使用最小花费爬楼梯

Codefun2000

  1. 华为 P1004. 2022.9.23-求和
  2. 民生科技 P1215. 2023.04.22-技术研发春招-第二题-收集大写字母
  3. 小红书 P1039. 2022.9.11-最佳爬楼方案

代码

CPP

#include <bits/stdc++.h>
using namespace std;

const int MOD = 1e9 + 7;

int main()
{
    ios::sync_with_stdio(false);
    cin.tie(nullptr);

    int n, P, K;
    cin >> n >> P >> K;

    for (int turn = 0; turn < n; ++turn) {
        int m; cin >> m;
        vector<int> h(m + 1);

        bool ok = true;
        for (int i = 1; i <= m; ++i) {
            cin >> h[i];
            // 如果存在一个台阶的高度大于 P ,那无论如何也不可能爬完所有台阶
            if (h[i] > P) {
                ok = false;
            }
        }

        if (!ok) {
            cout << "0\n";
        } else {
            vector<int> dp(m + 1, 0);
            dp[0] = 1;
            for (int i = 1; i <= m; ++i) {
                // height 表示从 j + 1 到 i 这些台阶的总高度
                // 同时满足 i - j <= K
                int height = h[i];
                for (int j = i - 1; j >= max(i - K, 0) && height <= P; --j) {
                    dp[i] = (dp[i] + dp[j]) % MOD;
                    height += h[j];
                }
            }
            cout << dp[m] << "\n";
        }

    }

    return 0;
}

python

MOD = 10**9 + 7

n, P, K = map(int, input().split())

for turn in range(n):
    h = list(map(int, input().split()))
    m = h[0]

    ok = True
    for i in range(1, m + 1):
        # 如果存在一个台阶的高度大于 P ,那无论如何也不可能爬完所有台阶
        if h[i] > P:
            ok = False

    if not ok:
        print(0)
    else:
        dp = [0] * (m + 1)
        dp[0] = 1
        for i in range(1, m + 1):
            # height 表示从 j + 1 到 i 这些台阶的总高度
            # 同时满足 i - j <= K
            height = h[i]
            for j in range(i - 1, max(i - K - 1, -1), -1):
                if i - j > K:
                    break
                dp[i] = (dp[i] + dp[j]) % MOD
                if height + h[j] > P:
                    break
                height += h[j]
        print(dp[m])

Java

import java.util.*;

public class Main {
    public static void main(String[] args) {
        Scanner in = new Scanner(System.in);
        int n = in.nextInt();
        int P = in.nextInt();
        int K = in.nextInt();

        for (int turn = 0; turn < n; ++turn) {
            int m = in.nextInt();
            int[] h = new int[m + 1];

            boolean ok = true;
            for (int i = 1; i <= m; ++i) {
                h[i] = in.nextInt();
                // 如果存在一个台阶的高度大于 P ,那无论如何也不可能爬完所有台阶
                if (h[i] > P) {
                    ok = false;
                }
            }

            if (!ok) {
                System.out.println("0");
            } else {
                int MOD = 1000000007;
                int[] dp = new int[m + 1];
                dp[0] = 1;
                for (int i = 1; i <= m; ++i) {
                    // height 表示从 j + 1 到 i 这些台阶的总高度
                    // 同时满足 i - j <= K
                    int height = h[i];
                    for (int j = i - 1; j >= Math.max(i - K, 0) && height <= P; --j) {
                        dp[i] = (dp[i] + dp[j]) % MOD;
                        height += h[j];
                    }
                }
                System.out.println(dp[m]);
            }

        }
    }
}

Go

package main

import "fmt"

const MOD = 1000000007

func main() {
    var n, P, K int
    fmt.Scan(&n, &P, &K)

    for turn := 0; turn < n; turn++ {
        var m int
        fmt.Scan(&m)
        h := make([]int, m+1)

        ok := true
        for i := 1; i <= m; i++ {
            fmt.Scan(&h[i])
            // 如果存在一个台阶的高度大于 P ,那无论如何也不可能爬完所有台阶
            if h[i] > P {
                ok = false
            }
        }

        if !ok {
            fmt.Println(0)
        } else {
            dp := make([]int, m+1)
            dp[0] = 1
            for i := 1; i <= m; i++ {
                // height 表示从 j + 1 到 i 这些台阶的总高度
                // 同时满足 i - j <= K
                height := h[i]
                for j := i - 1; j >= max(i-K, 0) && height <= P; j-- {
                    dp[i] = (dp[i] + dp[j]) % MOD
                    height += h[j]
                }
            }
            fmt.Println(dp[m])
        }

    }
}

func max(a, b int) int {
    if a > b {
        return a
    }
    return b
}

Js

process.stdin.resume();
process.stdin.setEncoding('utf-8');
let input = '';
process.stdin.on('data', (data) => {
    input += data;
    return;
});
process.stdin.on('end', () => {
    const lines = input.trim().split('\n');
    const MOD = 1000000007;
    let index = 0;
    const [n, P, K] = lines[index++].trim().split(' ').map(Number);
    for (let turn = 0; turn < n; turn++) {
        const h = lines[index++].trim().split(' ').map(Number);
        let m = h[0]

        let ok = true;
        for (let i = 1; i <= m; i++) {
            if (h[i] > P) {
                ok = false;
            }
        }

        if (!ok) {
            console.log('0');
        } else {
            const dp = new Array(m + 1).fill(0);
            dp[0] = 1;
            for (let i = 1; i <= m; i++) {
                let height = h[i];
                for (let j = i - 1; j >= Math.max(i - K, 0) && height <= P; j--) {
                    dp[i] = (dp[i] + dp[j]) % MOD;
                    height += h[j];
                }
            }
            console.log(dp[m]);
        }
    }
});

题目内容均收集自互联网,如如若此项内容侵犯了原著者的合法权益,可联系我: (CSDN网站注册用户名: 塔子哥学算法) 进行删除。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

塔子哥学算法

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值