提高计算递归序列的速度

时间:2017-04-24 14:40:52

标签: c#

我正试图用c#

来解决这个问题
  

使用自然数,可以使用以下过程:
  在给定数字的右侧键入0   在给定数字的右侧键入4号   将数字除以2
  如果给出第55号,可以获得以下数字:2003,2004,2005,2006,2007
  (((((如果我们获得32号,那么我们可以获得这些数字中的任何一个:2003,2004,2005,2006,2007)))
  我们可以通过28个步骤找到解决方案。

所以我写了这段代码:

   static void Main(string[] args)
  {
    long number = 550, goal = 32;
    int count = 0;
    bool flag = false;
    find(number, goal, count, flag);
    Console.WriteLine("Done");
    Console.ReadKey();
 }
 static bool find(long number, long goal, int count, bool flag)
 {
     if(number==goal) { Console.WriteLine(number); return true; }
     if(count ==28 && number != goal) { return false;}
     else
     {
         flag =find(number*10, goal, count+1, flag); 
         if (flag == true) {  Console.WriteLine(number); return flag; }
         flag = find(number * 10 + 4, goal, count + 1, flag);
          if (flag == true) { Console.WriteLine(number); return flag;  }
         if (number % 2 == 0) {
            flag= find(number / 2, goal, count + 1, flag);
           if (flag == true) { Console.WriteLine(number); return flag; 
         } }
         return flag;
         }
       }

任何人都可以加速递归进度

1 个答案:

答案 0 :(得分:0)

您的实施很简单,但很天真。它会经历所有可能性,直到找到匹配为止。经过一番思考,你实际上可以淘汰大部分计算。

当您的递归代码执行时,每个递归调用分成3个路径,使其最多为 3 ^ 28 不同的可能性。这是最糟糕的情况,当方法的结果是错误的。一旦找到第一条路径,您的代码就会解析,但很有可能会浪费大量时间进行必要的计算。

我将以你的数字为例,所以我可以说清楚:

  

假设我进行以下调用:find(550,32,0,false);

     

在某个时间点,您的程序将沿着它的路径前进   将不断乘以550乘以10.但为什么要将它乘以10   如果32小于550?

     

在另一个时间点,您的程序将沿着它的路径前进   将乘以550乘以10并连续加4。但和以前一样,为什么呢   当目标较小时继续上升?

     

所以这是最后的结论:

     

数字 =传递给参数的当前值,数字。

     

remIteration =剩余的递归调用次数。 (28 - 当前递归调用#)

     

maxDivisor = 2 ^ x。这是当前值可以除以的最大值。

     

smallestFuture = number / maxDivisor。

     

基本上, smallestFuture 是来自的最小可能值   当前的递归调用。它是通过不断划分来计算的   当前数字2,直到递归计数达到28.然后,如果    smallestFuture 仍然大于目标号码,会有   没有必要计算当前路径下的计算。

以下是我写的代码。函数调用被修改,因为我认为使用flag参数没有意义。如果您愿意,请随意添加。

static bool find(long number, long goal, int count)
{
    if (number == goal)
    {
        Console.WriteLine(number);
        return true;
    }

    if (count == 28 && number != goal)
        return false;

    int remIteration = 28 - count;
    long maxDivisor = (long)Math.Pow(2, remIteration);
    long smallestFuture = number / maxDivisor;

    if (smallestFuture > goal)
        return false;

    if (smallestFuture == goal)
    {
        Console.WriteLine(number);
        return true;
    }

    long newNumber = number * 10;
    int nexCount = count + 1;

    if (find(newNumber, goal, nexCount) || find(newNumber + 4, goal, nexCount))
    {
        Console.WriteLine(number);
        return true;
    }

    if (number % 2 == 0)
    {
        if (find(number / 2, goal, nexCount))
        {
            Console.WriteLine(number);
            return true;
        }
    }

    return false;
}

不幸的是,我现在没有足够的时间使用dynamic programming来解决这个问题,但它肯定会提供比我的代码更好的性能。请注意,我的代码与您的代码非常相似,会打印出它检测到的第一个可能的路径,而不是最佳路径。