# 18. 少儿爬山闯关积分游戏

# 题目内容

山路一共设有 n 个关卡,按 1 ∼ n 顺序排列。当前位于 1 号关卡,必须按照关卡从小到大闯关,且必须到达最后第 n 号关卡才算寻宝成功。每个关卡都有对应的宝藏分值(可能为负数),经过当前关卡即可获得该关卡分值,分数持续累加。

移动规则:

  • 从当前关卡,下一次只能在前方 1 关或者 2 关处打卡;
  • 限制规则:不能连续两次都一次性跳 2 关,违反该规则的路线无效;

请求出:所有合法路线中,能够收集到的最大累加总分。

# 输入描述

  • 参数 1:整数 n,代表关卡数量
  • 参数 2:整数数组,依次表示第 1 ∼ n 关的宝藏分值
  • 1 ≤ n ≤ 20
  • 每关分值:−999 ≤ val ≤ 999

# 输出描述

输出一个整数,代表合法路线的最大累加得分。

# 样例

# 样例 1

输入

5
10 5 8 3 15
1
2

输出

41
1

说明:

  • 合法路线示例:1→2→3→4→5,无连续跳两关,总分:10+5+8+3+15=41
  • 路线 1→3→5 连续两次跳 2 关,违规,不计入统计。

# 样例 2

输入

4
10 1 1 100
1
2

输出

112
1

说明:

  • 路线 1→2→3→4(1,1,1):10+1+1+100=112
  • 路线 1→3→4(2,1):10+1+100=111
  • 路线 1→2→4(1,2):10+1+100=111

最大值 112。

# 代码

const readline = require('readline');
const rl = readline.createInterface({
    input: process.stdin,
    output: process.stdout,
});

rl.on('line', (input) => {
    const n = Number(input);
    rl.on('line', (input) => {
        let max = -Infinity;
        const arr = input.split(' ').map(Number);
        if (n === 1) {
            console.log(arr[0]);
            return;
        }
        const dfs = (i, lastJumpTwo, sum) => {
            if (i === n - 1) {
                max = Math.max(max, sum);
                return;
            }
            // 走1步
            if (i + 1 < n) {
                dfs(i + 1, false, sum + arr[i + 1]);
            }
            // 走2步,前提是上一次不是跳2步来的
            if (!lastJumpTwo && i + 2 < n) {
                dfs(i + 2, true, sum + arr[i + 2]);
            }
        };

        dfs(0, false, arr[0]);
        console.log(max);
    })
})



1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37

或者

const readline = require('readline');
const rl = readline.createInterface({
    input: process.stdin,
    output: process.stdout,
});

let lineCount = 0;
let n, arr;

rl.on('line', (input) => {
    if (lineCount === 0) {
        n = Number(input);
        lineCount++;
    } else {
        arr = input.split(' ').map(Number);
        
        // 边界:只有1关
        if (n === 1) {
            console.log(arr[0]);
            rl.close();
            return;
        }
        
        // dp[i][0]: 到第i关,上一步走1关
        // dp[i][1]: 到第i关,上一步跳2关
        // 初始化负无穷,表示不可达
        const dp = Array.from({ length: n }, () => [-Infinity, -Infinity]);
        
        // 第0关(第1关):初始就在这里,没有"上一步"
        // 可以理解为"上一步走1关"到达起点
        dp[0][0] = arr[0];
        dp[0][1] = -Infinity; // 不可能跳2关到起点
        
        // 第1关(第2关)
        if (n >= 2) {
            // 只能从第0关走1关来
            dp[1][0] = dp[0][0] + arr[1];
            // 不能从-1关跳2关来
            dp[1][1] = -Infinity;
        }
        
        // 从第2关开始递推
        for (let i = 2; i < n; i++) {
            // 上一步走1关:可以从i-1走1或跳2来,取最大
            dp[i][0] = Math.max(dp[i-1][0], dp[i-1][1]) + arr[i];
            
            // 上一步跳2关:只能从i-2走1关来(不能从i-2跳2关来,否则连续两次跳2)
            dp[i][1] = dp[i-2][0] + arr[i];
        }
        
        // 答案是到达最后一关的两种状态的最大值
        const result = Math.max(dp[n-1][0], dp[n-1][1]);
        console.log(result);
        rl.close();
    }
});
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56