确定最大乐趣的算法

时间:2012-02-15 20:20:39

标签: c++ algorithm

可以找到问题本身here。它的主旨是Bessie坐过山车,但她头晕目眩。如果不超过她的“头晕限制”,她可以获得的最大乐趣是多少。 输入包括:

N K L

其中N(1≤N≤1,000)是特定过山车中的截面数; K(1≤K≤500)是如果她在骑行的任何部分闭上眼睛,Bessies头晕水平下降的量;和L(1≤L≤300,000)是Bessie可以忍受的头晕的极限 - 如果她的头晕变得比L大,Bessie会生病,那不好玩!

接下来的N行中的每一行都有两个整数:

F D

其中F(1≤F≤20)是如果她在该部分睁开眼睛就会获得Bessies总乐趣的增加,而D(1≤D≤500)是她的头晕水平的增加,如果她在那一节睁大眼睛。这些部分将按顺序列出。“

我解决此问题的算法如下:

        cin >> N; // sections
        cin >> K; // amount dizziness can go down
        cin >> L; // dizzy ceiling
        belowL = L; // sets the amount of dizzy left

        for (int i = 0; i < N; i++) {
            cout << "\n" << i;
            cin >> F >> D; // fun increase and dizzy increase
            if (D < belowL) {
                if (F >= D) {
                    funTotal += F;
                }
            }
            else {
                belowL -= K;
            }

但是,这不会总是产生正确的结果。问题是什么?它应该选择有趣的选项,除非它会使Bessie超过疾病阈值。有没有更好的方法呢?

2 个答案:

答案 0 :(得分:8)

所以不要在这里给你代码,而是对问题解决方案的一种解释。

基本方法是使用动态编程来解决,因为这会减少到所谓的Knapsack problem。想到这一点,她的头晕是她能够立刻携带多少钱而且她想要最大化的乐趣(相比之下,她带着麻袋里的“物品”的价值)。现在我们想要做的就是从过山车中获得最大的乐趣(最重要的是在麻袋中)而不会让她太晕眩(超过麻袋上的“重量”限制)。

所以现在你想要选择她的眼睛打开/关闭的部分(物品是否在麻袋中)。因此,想到这一点的简单方法是选择两个选项的最大值。如果她能够在不超过门槛的情况下睁大眼睛,或者是否只是闭着眼睛。但现在问题发生了变化,你看她是否睁着眼睛,她的眩晕阈值会降低(更容易解决子问题)。

使用这些信息可以很容易地使背包解决方案适应这个问题,而不必使用回溯或递归。

我们的想法是将所有先前解决的子问题保存在矩阵中,以便您可以重复使用结果,而不是每次重新计算结果。请注意,您可以使用的一个技巧是您只需要矩阵的当前行和之前解决的行,因为背包的递归关系仅需要这些条目:)

P.S我在这个地方遇到了这个问题并解决了它,很高兴再次看到这个问题

答案 1 :(得分:5)

  

它应该选择有趣的选项,除非它会让Bessie超过   疾病阈值。有没有更好的方法呢?

问题在于你没有最大化这里的乐趣,你只是在阻止Bessie生病。当你到达一个会让她超过头晕目标的部分时,你可以通过回溯和在之前的某个部分采用不好玩的选项来增加更多的乐趣。假设您有这样的输入,按F D顺序:

1 400
5 450
10 25
18 75
20 400

此外,让我们说当她击中上面的第一部分时,她已经接近眩晕极限了。你可以在前两个部分采取有趣的选项,并获得F增加6和D增加850.也许这使她正确的极限。现在你别无选择,只能为后续部分选择无趣的选项。另一方面,如果你对前两个部分选择了无趣的选项,你可以为接下来的三个部分选择有趣的选项,并且如果D的增加只有500,则增加F为48。

如果F:D比率大于1并且您还有足够的眩晕能力,那么您当前的算法会采用有趣的选项。这是合理的,但不是最优的。没有固定比率可能会给出最佳解决方案。相反,您需要考虑每个部分的每个选项的好处和成本。