2009-08-21 77 views
1

我正在创建一个预测应用程序,该程序将运行生产工厂能够运行的各种“模式”的模拟。该工厂每天可以运行一种模式,因此我正在编写一个功能,将每日选择的不同模式相加,最大限度地提高工厂的产量,并与所提供的销售预测数字保持最佳匹配。这些数据将被加载到一个模式对象的数组中,然后用于计算工厂的预测输出。帮助创建递归函数C#

我已经创建了这个功能,但是,我需要使它们递归,以便能够处理模式和工作日(根据生产需要而变化)的任何数量(合理范围内)。下面列出的是我使用for循环来模拟我想要做什么的代码。有人能指出我正确的方向,以创建一个递归函数来取代多个for循环的需要吗?

其中GetNumbers4方法将有四种模式,而GetNumbers5将有5种模式。诠释开始将是工作日的数量。

private static void GetNumber4(int start) 
    { 
     int count = 0; 
     int count1 = 0;   

     for (int i = 0; 0 <= start; i++) 
     { 
      for (int j = 0; j <= i; j++) 
      { 

       for (int k = 0; k <= j; k++) 
       { 
        count++; 

        for (int l = 0; l <= i; l++) 
        { 
         count1 = l; 
        } 

        Console.WriteLine(start + " " + (count1 - j) + " " + (j - k) + " " + k); 
        count1 = 0; 
       } 

      } 
      start--; 

     } 
     Console.WriteLine(count); 

    } 

    private static void GetNumber5(int start) 
    { 
     int count = 0; 
     int count1 = 0; 

     for (int i = 0; 0 <= start; i++) 
     { 
      for (int j = 0; j <= i; j++) 
      { 

       for (int k = 0; k <= j; k++) 
       { 

        for (int l = 0; l <= k; l++) 
        { 
         count++; 
         for (int m = 0; m <= i; m++) 
         { 
          count1 = m; 
         } 
         Console.WriteLine(start + " " + (count1 - j) + " " + (j - k) + " " + (k - l) + " " + l); 
         count1 = 0; 
        } 

       } 

      } 
      start--; 

     } 
     Console.WriteLine(count); 

    } 

编辑:

我认为,这将是更有帮助,如果我给什么,我试图做一个例子。例如,如果一个工厂可以以“A”,“B”,“C”三种模式运行并且有三个工作日,那么代码将返回以下结果。

3 0 0 
2 1 0 
2 0 0 
1 2 0 
1 1 1 
1 0 2 
0 3 0 
0 2 1 
0 1 2 
0 0 3 

的一系列数字表示的三种模式A B C.我将这些结果加载到具有相应的生产速率的模式的对象。这样做可以让我快速创建每种可能组合的列表;它反而给我一个发生的频率。

基于已经提供的解决方案之一,我想要做这样的事情。

//Where Modes is a custom classs 
    private static Modes GetNumberRecur(int start, int numberOfModes) 
    { 
     if (start < 0) 
     { 
      return Modes; 

     } 

     //Do work here 
     GetNumberRecur(start - 1); 
    } 

感谢大家谁已经提供了输入。

+2

你永远不需要*递归函数。任何你可以递归地做的事情都可以迭代地完成,有些问题只适用于递归,就像遍历一个文件系统一样。 – 2009-08-21 20:06:46

+0

为什么不算1做任何事情? – Jimmy 2009-08-21 20:10:54

+0

Count1用于将最内循环的结果传递给循环外的console.writeline。 – 2009-08-21 20:19:37

回答

6

调用GetNumber(5,X)应产生相同的结果GetNumber5( X):

static void GetNumber(int num, int max) { 
    Console.WriteLine(GetNumber(num, max, "")); 
} 
static int GetNumber(int num, int max, string prefix) { 
    if (num < 2) { 
     Console.WriteLine(prefix + max); 
     return 1; 
    } 
    else { 
     int count = 0; 
     for (int i = max; i >= 0; i--) 
      count += GetNumber(num - 1, max - i, prefix + i + " "); 
     return count; 
    } 
} 
+0

你绝对钉上它。非常感谢。 – 2009-08-21 20:54:18

+0

说实话,一个更好的解决方案可能会涉及GetNumber产生一个int []或者其他东西的迭代器,所以你的其他组件可以直接获取这些值。 – Jimmy 2009-08-21 21:25:32

0

我以前提供了一个简单的C#递归函数here。 最顶级的功能最终得到每个排列的副本,所以它应该很容易适应您的需求。

4

递归函数只需要终止条件。在你的情况,这似乎是在start小于0:

private static void GetNumberRec(int start) 
{ 
    if(start < 0) 
    return; 

    // Do stuff 

    // Recurse 
    GetNumberRec(start-1); 
} 
1

我已经重构你的榜样这个:

private static void GetNumber5(int start) 
{ 
    var count = 0; 

    for (var i = 0; i <= start; i++) 
    { 
     for (var j = 0; j <= i; j++) 
     { 
      for (var k = 0; k <= j; k++) 
      { 
       for (var l = 0; l <= k; l++) 
       { 
        count++; 

        Console.WriteLine(
         (start - i) + " " + 
         (i - j) + " " + 
         (j - k) + " " + 
         (k - l) + " " + 
         l); 
       } 
      } 
     } 
    } 

    Console.WriteLine(count); 
} 

请确认这是正确的。然后

递归版本应该是这样的:

public static void GetNumber(int start, int depth) 
{ 
    var count = GetNumber(start, depth, new Stack<int>()); 
    Console.WriteLine(count); 
} 

private static int GetNumber(int start, int depth, Stack<int> counters) 
{ 
    if (depth == 0) 
    { 
     Console.WriteLine(FormatCounters(counters)); 
     return 1; 
    } 
    else 
    { 
     var count = 0; 
     for (int i = 0; i <= start; i++) 
     { 
      counters.Push(i); 
      count += GetNumber(i, depth - 1, counters); 
      counters.Pop(); 
     } 
     return count; 
    } 
} 

FormatCounters留给读者作为练习到读取器)

0

我意识到,每个人都打了我一记重拳,在这一点上,但这里有一个愚蠢的Java算法(很接近C#语法ŧ帽子,你可以尝试)。

import java.util.ArrayList; 
import java.util.List; 

/** 
* The operational complexity of this is pretty poor and I'm sure you'll be able to optimize 
* it, but here's something to get you started at least. 
*/ 
public class Recurse 
{ 
    /** 
    * Base method to set up your recursion and get it started 
    * 
    * @param start The total number that digits from all the days will sum up to 
    * @param days The number of days to split the "start" value across (e.g. 5 days equals 
    * 5 columns of output) 
    */ 
    private static void getNumber(int start,int days) 
    { 
     //start recursing 
     printOrderings(start,days,new ArrayList<Integer>(start)); 
    } 

    /** 
    * So this is a pretty dumb recursion. I stole code from a string permutation algorithm that I wrote awhile back. So the 
    * basic idea to begin with was if you had the string "abc", you wanted to print out all the possible permutations of doing that 
    * ("abc","acb","bac","bca","cab","cba"). So you could view your problem in a similar fashion...if "start" is equal to "5" and 
    * days is equal to "4" then that means you're looking for all the possible permutations of (0,1,2,3,4,5) that fit into 4 columns. You have 
    * the extra restriction that when you find a permutation that works, the digits in the permutation must add up to "start" (so for instance 
    * [0,0,3,2] is cool, but [0,1,3,3] is not). You can begin to see why this is a dumb algorithm because it currently just considers all 
    * available permutations and keeps the ones that add up to "start". If you want to optimize it more, you could keep a running "sum" of 
    * the current contents of the list and either break your loop when it's greater than "start". 
    * 
    * Essentially the way you get all the permutations is to have the recursion choose a new digit at each level until you have a full 
    * string (or a value for each "day" in your case). It's just like nesting for loops, but the for loop actually only gets written 
    * once because the nesting is done by each subsequent call to the recursive function. 
    * 
    * @param start The total number that digits from all the days will sum up to 
    * @param days The number of days to split the "start" value across (e.g. 5 days equals 
    * 5 columns of output) 
    * @param chosen The current permutation at any point in time, may contain between 0 and "days" numbers. 
    */ 
    private static void printOrderings(int start,int days,List<Integer> chosen) 
    { 
     if(chosen.size() == days) 
     { 
      int sum = 0; 
      for(Integer i : chosen) 
      { 
       sum += i.intValue(); 
      } 

      if(sum == start) 
      { 
       System.out.println(chosen.toString()); 
      } 
      return; 
     } 
     else if(chosen.size() < days) 
     { 
      for(int i=0; i < start; i++) 
      { 
       if(chosen.size() >= days) 
       { 
        break; 
       } 

       List<Integer> newChosen = new ArrayList<Integer>(chosen); 
       newChosen.add(i); 
       printOrderings(start,days,newChosen); 
      } 
     } 
    } 

    public static void main(final String[] args) 
    { 
     //your equivalent of GetNumber4(5) 
     getNumber(5,4); 

     //your equivalent of GetNumber5(5) 
     getNumber(5,5); 
    } 
}