【问题标题】:TCS MockVita 2019 Round 2 Question: Hop GameTCS MockVita 2019 第 2 轮问题:Hop Game
【发布时间】:2019-10-31 09:18:26
【问题描述】:

我正在尝试解决 TCS MockVita 2019 第 2 轮中提出的问题:

问题描述

高斯学校的数学老师 Felix Kline 博士介绍了以下游戏来教他的学生解决问题。他将一系列“跳石”(纸片)排成一条直线,每个跳石上都标有点(正数)。

学生从一端开始跳到另一端。一个人可以踩到一块石头并将石头上的数字加到他们的累积分数中,或者跳过一块石头并落在下一块石头上。在这种情况下,他们会获得两倍于他们着陆的石头上标记的分数,但不会获得他们跳过的石头上标记的分数。

在旅途中最多允许学生(如果他们选择)进行“二段跳”——也就是说,他们跳过两个连续的石头——在那里他们将获得三倍于他们着陆的石头的分数上,但不是他们跳过的石头的点。

老师希望他的学生做一些思考并想出一个计划来获得尽可能高的分数。给定石头序列上的数字,编写一个程序来确定可能的最高分数。

约束

序列中的石头数

输入格式

第一行包含N,整数个数(这是一个正整数)

下一行包含用逗号分隔的 N 个点(每个点都是正整数)。这些是石头上的点,按照石头的放置顺序。

输出

代表最高分的一个整数

测试用例

解释

示例 1

输入

3

4,2,3

输出

10

解释

有3个石头(N=3),点数(按排列顺序)分别是4,2和3。

如果我们踩第一块石头跳过第二块得到4 + 2 x 3 = 10。双跳到第三块石头只会得到9。因此结果是10,并且没有使用双跳

示例 2

输入

6

4,5,6,7,4,5

输出

35

解释

N=6,点数顺序给定。获得35的一种方法是先双跳到3号石子(3 x 6=18),再到4号石子(7),再跳到6号石子(10分)一共35分。二段跳只用了一次,结果是35分。

我发现这是一个动态编程问题,但我不知道我做错了什么,因为我的解决方案无法通过所有测试用例。我的代码通过了我创建的所有测试。

unordered_map<int, int> lookup;
int res(int *arr, int n, int i){

    if(i == n-1){
        return 0;
    }

    if(i == n-2){
        return arr[i+1];
    }

    if(lookup.find(i) != lookup.end())
        return lookup[i];

    int maxScore = 0;

    if(i< n-3 && flag == false){
        flag = true;
        maxScore = max(maxScore, 3 * (arr[i+3]) + res(arr, n, i+3));
        flag = false;
    }
    maxScore = max(maxScore, (arr[i+1] + res(arr,n,i+1)));

    lookup[i] = max(maxScore, 2 * (arr[i+2]) + res(arr, n, i+2));

    return lookup[i];
}

cout << res(arr, n, 0) + arr[0];  // It is inside the main()

我希望您能在我的代码中找到错误并给出正确的解决方案,以及任何未能通过此解决方案的测试用例。谢谢:)

【问题讨论】:

  • 您应该尝试使您的解决方案非递归。此外,解释您的解决方案并使用描述性变量名称将使代码更易于理解。
  • @JuanCarlosRamirez 请查看我在list of revisions 上留下的说明。

标签: c++ algorithm dynamic-programming


【解决方案1】:

您不需要任何地图。您只需要记住最后几个最大值。每一步你有两个选择(除了两个第一),以双跳结束或没有它。如果您不想做 dj,那么您最好的选择是最大的最后一块石头 + 当前和最后一块石头 + 2 * 当前 max(no_dj[2] + arr[i], no_dj[1] + 2 * arr[i])

另一方面,如果你想制作 dj,那么你有三个选择,要么在前一个 dj dj[2] + arr[i] 之后跳一个石头,要么在一些 dj dj[1] + 2 * arr[i] 之后跳过最后一个石头,或者在当前动作中进行双跳no_dj[0] + 3 * arr[i].

int res(int *arr, int n){
    int no_dj[3]{ 0, 0, arr[0]};
    int dj[3]{ 0, 0, 0};

    for(int i = 1; i < n; i++){
        int best_nodj = max(no_dj[1] + 2 * arr[i], no_dj[2] + arr[i]);
        int best_dj = 0;
        if(i > 1) best_dj = max(max(dj[1] + 2 * arr[i], dj[2] + arr[i]), no_dj[0] + 3 * arr[i]);

        no_dj[0] = no_dj[1];
        no_dj[1] = no_dj[2];
        no_dj[2] = best_nodj;
        dj[0] = dj[1];
        dj[1] = dj[2];
        dj[2] = best_dj;
    }
    return max(no_dj[2], dj[2]);
}

您只需要记住三个元素的两个数组。双跳后的最后三个最大值和没有双跳的最后三个最大值。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-10-31
    相关资源
    最近更新 更多