C# Как напечатать комбинации, суммирующиеся с заданным числом? - PullRequest
1 голос
/ 06 мая 2020

Я пытаюсь реализовать проблему «Подсчет различных способов express N как сумму других чисел» с C# с использованием динамического c программирования. Мой метод выглядит так:

 static int howManyWays(int n) 
    { 
        int [] safe= new int[n + 1]; 

        // base cases 
        safe[0] = safe[1] = safe[2] = 1; 
        safe[3] = 2; 

        // iterate for all values from 4 to n 
        for (int i = 4; i <= n; i++) 
            safe[i] = safe[i - 1] + safe[i - 3]  
                    + safe[i - 4]; 

        return safe[n]; 
    } 

Например, если я выберу n как n = 4, то мои результаты будут:

4 

Я хочу распечатать эти 4 комбинации сумм:

 1+1+1+1 
 1+3
 3+1 
 4 

Есть ли способ сделать это рекурсивно или с использованием динамического c программирования? Моя попытка - рекурсивно получить набор комбинаций:

static int[]  Combs(int n)
        {
            int[] tusc = { };

            if (n < 0)
                yield break;
            if (n == 0)
                yield return tusc;
            int[] X = { 1, 3, 4 };
            for(int i = 0; i < X.Length; i++)
            {
                for(j = 0; j <= Combs(n-X[i]).Length; j++)
                {
                    yield return X + j;
                }

            }

        }

Исходный код, который работает в python, но не знаю, как преобразовать в C#:

def combis(n):
    if n < 0:
        return
    if n == 0:
        yield []
    for x in (1, 3, 4):
        for combi in combis(n-x):
            yield [x] + combi

>>> list(combis(5))
[[1, 1, 1, 1, 1], [1, 1, 3], [1, 3, 1], [1, 4], [3, 1, 1], [4, 1]]

1 Ответ

1 голос
/ 07 мая 2020

Вот довольно прямой перевод:

using System;
using System.Collections.Generic;

class MainClass 
{
    static IEnumerable<List<int>> Combs(int n)
    {
        if (n < 0)
        {
            yield break;
        } 
        else if (n == 0) 
        {
            yield return new List<int>();
        }

        foreach (int x in new List<int>() {1, 3, 4})
        {
            foreach (IEnumerable<int> combi in Combs(n - x))
            {       
                var result = new List<int>() {x};
                result.AddRange(combi);
                yield return result;
            }

        }
    }

    public static void Main(string[] args) 
    {
        foreach (IEnumerable<int> nums in Combs(5))
        {
            foreach (var i in nums) 
            {
                Console.Write(i + ", ");
            }

            Console.WriteLine();
        }
    }
}

Вывод:

1, 1, 1, 1, 1, 
1, 1, 3, 
1, 3, 1, 
1, 4, 
3, 1, 1, 
4, 1, 

Примечания:

  • Поскольку вы используете yield, измените заголовок Combs для возврата IEnumerable<int> вместо int[].
  • Используйте списки вместо массивов фиксированной длины и List.AddRange для преобразования операции конкатенации + списка из Python.
  • Есть некоторая путаница с переводом X. В версии Python x - это всего лишь один элемент в списке опций {1, 3, 4}, но в версии C# это весь массив.
  • Combs(n-X[i]).Length не имеет смысла - -it вызывает Combs, берет длину результатов и затем отбрасывает все результаты, так что это похоже на действительно дорогой счетчик. j дает вам индекс счетчика, а не один из элементов из дочернего вызова Combs, как предполагалось. foreach - наиболее точный перевод Python циклов for .. in.
  • Список {1, 3, 4}, вероятно, следует превратить в параметр, позволяющий вызывающему абоненту управлять своим поведением.
  • Низкая эффективность, поскольку пересчитываются перекрывающиеся подзадачи. Его улучшение оставлено как упражнение (в любом случае это, вероятно, был ваш следующий шаг).
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...