检查每个橄榄球得分的递归方式,不重复

时间:2011-09-02 18:56:29

标签: c++ algorithm recursion

为了好玩,我创建了一个算法,根据给定的橄榄球得分(3,5或7分)计算每种可能的组合。我发现了两种方法:第一种是暴力,3种是叠加的for循环。另一个是递归。

问题是某些组合出现多次。我怎么能避免这种情况?

我的代码:

#include <iostream>
using namespace std;
void computeScore( int score, int nbTryC, int nbTryNC, int nbPenalties );

int main()
{
    int score = 0;
    while (true)
    {
        cout << "Enter score : ";
        cin >> score;
        cout << "---------------" << endl << "SCORE = " << score << endl
                << "---------------" << endl;

        // Recursive call
        computeScore(score, 0, 0, 0);
    }
    return 0;
}

void computeScore( int score, int nbTryC, int nbTryNC, int nbPenalties )
{
    const int tryC = 7;
    const int tryNC = 5;
    const int penalty = 3;

    if (score == 0)
    {
        cout << "* Tries: " << nbTryC << " | Tries NT: " << nbTryNC
                << " | Penal/Drops: " << nbPenalties << endl;
        cout << "---------------" << endl;
    }
    else if (score < penalty)
    {
        // Invalid combination
    }
    else
    {
        computeScore(score - tryC, nbTryC+1, nbTryNC, nbPenalties);
        computeScore(score - tryNC, nbTryC, nbTryNC+1, nbPenalties);
        computeScore(score - penalty, nbTryC, nbTryNC, nbPenalties+1);
    }
}

3 个答案:

答案 0 :(得分:3)

考虑这一点的一种方法是要意识到,只要你有一笔钱,就可以通过对所有值进行排序将其置于某种“规范”形式。例如,给定

20 = 5 + 7 + 3 + 5

您也可以将其写为

20 = 7 + 5 + 5 + 3

这为如何解决您的问题提供了一些不同的选项。首先,您可以随时对所有总和进行排序和记录,而不是两次输出相同的金额。这有一个问题,你最终会多次重复生成相同的总和,这是非常低效的。

另一种(更好的)方法是更新递归以稍微不同的方式工作。现在,您的递归工作总是在每一步添加3,5和7。这就是首先使一切无序的原因。另一种方法是考虑添加你要添加的所有7个,然后添加所有5个,然后全部3个。换句话说,你的递归会起到这样的作用:

 Let kValues = {7, 5, 3}

 function RecursivelyMakeTarget(target, values, index) {
      // Here, target is the target to make, values are the number of 7's,
      // 5's, and 3's you've used, and index is the index of the number you're
      // allowed to add.

      // Base case: If we overshot the target, we're done.
      if (target < 0) return;

      // Base case: If we've used each number but didn't make it, we're done.
      if (index == length(kValues)) return;

      // Base case: If we made the target, we're done.
      if (target == 0) print values; return;

      // Otherwise, we have two options:
      // 1. Add the current number into the target.
      // 2. Say that we're done using the current number.

      // Case one
      values[index]++;
      RecursivelyMakeTarget(target - kValues[index], values, index);
      values[index]--;

      // Case two
      RecursivelyMakeTarget(target, values, index + 1);
 }

 function MakeTarget(target) {
      RecursivelyMakeTarget(target, [0, 0, 0], 0);
 }

这里的想法是在添加任何5个之前添加你要使用的所有7个,并在添加任何3个之前添加任何5个。如果你看一下以这种方式形成的递归树的形状,你会发现没有两条路径最终会尝试相同的总和,因为当路径分支时,或者添加了一个不同的数字,或者递归选择开始使用系列中的下一个数字。因此,每个总和只生成一次,并且不会使用重复。

此外,上面的方法可以扩展到可以添加任意数量的值,所以如果橄榄球引入了一个值得15分的新超级目标,你可以更新kValues数组,一切都会好起来的细

希望这有帮助!

答案 1 :(得分:1)

每次找到解决方案时,您都可以将其存储在字典中(例如,一组字符串,字符串看起来像“TC-TNT-P”)

在打印解决方案之前,请确认它不在字典中。

答案 2 :(得分:-4)

嵌套的for循环是执行此操作的自然方式。使用递归只是愚蠢(正如你似乎已经发现的那样)。