通过递归达到数字42

时间:2016-11-06 21:15:32

标签: c++ algorithm recursion

我正在尝试创建一个用户输入数字(n)的熊游戏,程序将通过执行一些指定的步骤来查看它是否可以达到数字42。如果不能,则通知用户该号码无法达到目标。

以下是规则:

  1. 如果n是偶数,那么你可以准确地回馈n / 2只熊。
  2. 如果n可以被3或4整除,那么你可以将n的后两位数相乘并返回 很多熊。
  3. 如果n可以被5整除,那么你可以准确地回馈42只熊。
  4. 以下是一个例子:

    • 从250头开始
    • 由于250可以被5整除,你可以返回42只熊,留下208只熊。
    • 由于208是偶数,你可以返回一半的熊,留下104只熊。
    • 由于104是偶数,你可以退回一半的熊,留下52只熊。
    • 由于52可被4整除,因此您可以将最后两位数乘以(得到10)并返回 这10只熊。这让你有42只熊。
    • 你已达到目标!

    这是我到目前为止所拥有的:

    #include <iostream>
    
    using namespace std;
    
    bool bears(int n);
    
    int main(){
        int number;
    
        do{
            cout<<"enter the amount of bears (press 0 to stop the program): ";
            cin>>number;
            if (bears(number)){
                cout<<"you have reached the goal!"<<endl;
            }
    
            else{
                cout<<"sorry, you have not reached the goal."<<endl;
            }
    
        }while(number != 0);
    }
    
    bool bears(int n){
        if (n < 42){
            return false;
        }
    
        else if (n == 42){
            return true;
        }
    
        else{
            if (n % 5 == 0){
                return bears(n - 42);
            }
    
            else if(n % 2 == 0){
                return bears(n / 2);
            }
    
             else if(n % 4 == 0|| n % 3 == 0)
            {
                int one;
                int two;
                one=n%10;
                two=(n%100)/10;
                return bears(n - one * two);
            }  
        }
    }
    

    我的程序有基本规则,但是当我输入250个熊时,它说它无法达到目标。我了解代码中发生了什么以及为什么它无法达到指定的目标,但我如何使其成为通用的,这样它不仅可以用于250号,还可以用于其他数字:84。

2 个答案:

答案 0 :(得分:5)

@ Corristo的答案很好,但是可以使用类似的深度优先搜索算法,只需对代码进行最少的更改。我已删除多余的ifelse s(因为我们在每种情况下都会返回)。

这个函数的作用不是像你的解决方案那样使用贪婪的方法,而是测试所有个案,直到找到答案。只有当第一个条件(5的可除性)时,您的代码才会测试第二个条件,依此类推。

bool bears(int n){
    if (n < 42)
        return false;

    if (n == 42)
        return true;

    // Moves on if condition isn't satisfied
    if ((n % 5 == 0) && bears(n - 42)) return true;

    if ((n % 2 == 0) && bears(n / 2)) return true;

    if(n % 4 == 0|| n % 3 == 0)
    {
        int one;
        int two;
        one=n%10;
        two=(n%100)/10;
        return one * two != 0 && bears(n - one * two);
    }  

    return false;
}

您可以尝试使用存储结果的缓存(std::map)进一步优化它,如果您之前已经计算过,则返回存储的结果,但它只在极少数情况下有用。

答案 1 :(得分:1)

由于我们没有任何关于我们需要为特定数字选择哪条规则的先验知识,最简单的方法是通过探索整个状态空间来尝试所有这些规则。您可以将其视为隐式给定图形中的可达性问题。

解决此类可达性问题的一种方法是使用先呼吸或深度优先搜索,这可以递归实现。

对于您的游戏,可以通过修改bears函数来获取整数的std::vector来检查它是否包含至少一个可以达到42的数字。

使用深度优先搜索,它可能如下所示:

bool bears(std::vector<int> ns) {
    // first remove all numbers < 42 since the goal cannot be reached from them
    ns.erase(std::remove_if(std::begin(ns), std::end(ns),
                            [] (auto const& n) { return n < 42; }),
             std::end(ns));

    if (ns.empty()) {
        return false;
    } else  if (std::any_of(std::cbegin(ns),
                            std::cend(ns),
                            [] (auto const& n) { return n == 42; })) {
        return true;
    } else {
       auto possible_number_of_bears = std::vector<std::vector<int>>{};
       std::transform(std::cbegin(ns),
                      std::cend(ns),
                      std::back_inserter(possible_number_of_bears),
                      [] (auto const& n) {
                            auto after_possible_rules = std::vector<int>{};
                            if (n % 5 == 0) {
                                after_possible_rules.emplace_back(n - 42);
                            }

                            if (n % 2 == 0) {
                                after_possible_rules.emplace_back(n / 2);
                            }

                            if (n % 4 == 0 || n % 3 == 0) {
                                int one;
                                int two;
                                one = n % 10;
                                two = (n % 100) / 10;
                                // avoid infinite recursion by only adding
                                // the new number if it is different from n
                                if (one * two != 0) {
                                    after_possible_rules.emplace_back(n - one * two);
                                }
                            }
                            return after_possible_rules; });
        return std::any_of(std::cbegin(possible_number_of_bears),
                           std::cend(possible_number_of_bears),
                           bears);
    }
}

现在您只需将调用代码调整为

 if (bears({number})) {
     std::cout << "you have reached the goal!" << std::endl;
 } else {
     std::cout << "sorry, you have not reached the goal." << std::endl;
 }

并相应地修改bears的前向声明。