#c# #list #recursion #numbers #add
Вопрос:
«Прошу всех, я пытался решить проблему, которая довольно странная. Я собираюсь привести пример, чтобы объяснить, чего я пытаюсь достичь.
У меня есть массив uint. Учитывая определенное число «n», как мне найти единственное решение, которое дает мне числа, суммируемые до «n»? Я говорю о «единственном решении», потому что есть только решение для достижения этого числа.
// This is not my array, but it's pretty similar.
// Given number: 96
// Used numbers to reach it: 32, 64
uint[] values = new uint[]
{
1,
2,
4,
8,
16,
32,
64,
128,
256,
512,
1024,
2048,
};
Ответ №1:
If values
— это список всех степеней числа (в вашем примере степени 2). Затем вы можете просто просмотреть список степеней от конца к началу, чтобы найти значения, которые выше числа, которое вы разбиваете на части, и вычесть их из числа (жадный метод):
private static IEnumerable<uint> FindParts(uint number, uint []powers)
{
for (var i = powers.Length - 1; i >= 0; i--)
{
if (number >= powers[i])
{
yield return powers[i];
number -= powers[i];
}
}
}
и используйте его как
uint randomNumber = (uint)new Random().Next(4095);
var parts = FindParts(randomNumber, values);
Console.WriteLine($"{randomNumber}={string.Join(' ', parts)}");
Ответ №2:
Ваша проблема — довольно простое математическое уравнение, поскольку все ваши числа равны степеням 2, вам лучше перейти на веб-сайт математики, чтобы изучить эти варианты
Однако, вот комбинаторный общий подход грубой силы для любого списка чисел
Учитывая
расширения unit sum
public static uint Sum(this IEnumerable<uint> source)
{
uint sum = 0;
checked
{
return source.Aggregate(sum, (current, v) => current v);
}
}
Способ получения комбинаций
public static IEnumerable<T[]> GetCombinations<T>(T[] source)
{
for (var i = 0; i < (1 << source.Length); i )
yield return source
.Where((t, j) => (i amp; (1 << j)) != 0)
.ToArray();
}
Способ фильтрации целей
public static IEnumerable<uint[]> GetTargets(IEnumerable<uint> source, uint target)
=> GetCombinations(source.ToArray())
.Where(items => items.Sum() == target);
Использование
uint[] values = { 1, 2, 4, 8, 16, 32, 64, 128, 256, 512, 1024, 2048, };
foreach (var found in GetTargets(values,96))
Console.WriteLine(string.Join(", ", found));
Вывод
32, 64
Примечание. если вы используете это с любым списком произвольного размера, ожидайте, что ответ будет ждать много жизней