Помогите с созданием рекурсивной функции C # - PullRequest
1 голос
/ 22 августа 2009

Я создаю приложение для прогнозирования, которое будет запускать симуляции для различных «режимов», которые может запустить производственное предприятие. Завод может работать в одном режиме в день, поэтому я пишу функцию, которая будет складывать различные режимы, выбранные каждый день, которые наилучшим образом максимизируют производительность завода и лучше всего соответствуют предоставленным прогнозам продаж. Эти данные будут загружены в массив объектов режима, которые затем будут использоваться для расчета прогнозируемой производительности завода.

Я создал функции, чтобы сделать это, однако мне нужно сделать их рекурсивными, чтобы я мог обрабатывать любое количество (в пределах разумного) режимов и рабочих дней (которые зависят от потребностей производства). Ниже приведен мой код, использующий циклы for для имитации того, что я хочу сделать. Может ли кто-нибудь указать мне правильное направление, чтобы создать рекурсивную функцию, чтобы заменить потребность в нескольких циклах for?

Где был бы метод GetNumbers4, когда было четыре режима, а GetNumbers5 - 5 режимов. Int start будет количество рабочих дней.

  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. Я загружу эти результаты в объект Modes, который имеет соответствующие показатели производительности. Делая это таким образом, я могу быстро создать список всех возможных комбинаций; вместо этого он дает мне частоту появления.

Опираясь на одно из уже предложенных решений, я бы хотел сделать что-то подобное.

    //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);
    }

Спасибо всем, кто уже предоставил информацию.

Ответы [ 5 ]

6 голосов
/ 22 августа 2009

Вызов 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;
    }
}
4 голосов
/ 22 августа 2009

Рекурсивной функции просто нужно завершающее условие. В вашем случае это, кажется, когда start меньше 0:

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

  // Do stuff

  // Recurse
  GetNumberRec(start-1);
}
1 голос
/ 22 августа 2009

Я реорганизовал ваш пример в это:

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 голосов
/ 22 августа 2009

Я понимаю, что в этот момент все меня опередили, но вот тупой алгоритм 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);
    }
}
0 голосов
/ 22 августа 2009

Ранее я предлагал простую рекурсивную функцию C # здесь . Самая верхняя функция заканчивается копией каждой перестановки, поэтому ее легко адаптировать к вашим потребностям.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...