Как я могу определить, может ли определенное число быть составлено из набора чисел?
Итак, у меня есть целое число, например, 1234567890, и данный набор цифр, например,{4, 7, 18, 32, 57, 68}
вопрос в том, может ли 1234567890 быть составлен из заданных чисел (вы можете использовать число более одного раза, и вам не нужно использовать все из них). В приведенном выше случае, одним из решений является:
38580246 * 32 + 1 * 18
(Не нужно давать конкретное решение, только если это можно сделать)
моей идеей было бы попробовать все решения. Например, я бы попробовал
1 * 4 * + 0 * 7 + 0 * 18 + 0 * 32 + 0 * 57 + 0 * 68 = 4
2 * 4 * + 0 * 7 + 0 * 18 + 0 * 32 + 0 * 57 + 0 * 68 = 8
3 * 4 * + 0 * 7 + 0 * 18 + 0 * 32 + 0 * 57 + 0 * 68 = 12
.....
308 641 972 * 4 * + 0 * 7 + 0 * 18 + 0 * 32 + 0 * 57 + 0 * 68 = 1234567888
308 641 973 * 4 * + 0 * 7 + 0 * 18 + 0 * 32 + 0 * 57 + 0 * 68 = 1234567892 ==> превышает
0 * 4 * + 1 * 7 + 0 * 18 + 0 * 32 + 0 * 57 + 0 * 68 = 7
1 * 4 * + 1 * 7 + 0 * 18 + 0 * 32 + 0 * 57 + 0 * 68 = 11
2 * 4 * + 1 * 7 + 0 * 18 + 0 * 32 + 0 * 57 + 0 * 68 = 15
и так далее...
вот мой код на C#:
static int toCreate = 1234567890;
static int[] numbers = new int[6] { 4, 7, 18, 32, 57, 68};
static int[] multiplier;
static bool createable = false;
static void Main(string[] args)
{
multiplier = new int[numbers.Length];
for (int i = 0; i < multiplier.Length; i++)
multiplier[i] = 0;
if (Solve())
{
Console.WriteLine(1);
}
else
{
Console.WriteLine(0);
}
}
static bool Solve()
{
int lastIndex = 0;
while (true)
{
int comp = compare(multiplier);
if (comp == 0)
{
return true;
}
else if (comp < 0)
{
lastIndex = 0;
multiplier[multiplier.Length - 1]++;
}
else
{
lastIndex++;
for (int i = 0; i < lastIndex; i++)
{
multiplier[multiplier.Length - 1 - i] = 0;
}
if (lastIndex >= multiplier.Length)
{
return false;
}
multiplier[multiplier.Length - 1 - lastIndex]++;
}
}
}
static int compare(int[] multi)
{
int osszeg = 0;
for (int i = 0; i < multi.Length; i++)
{
osszeg += multi[i] * numbers[i];
}
if (osszeg == toCreate)
{
return 0;
}
else if (osszeg < toCreate)
{
return -1;
}
else
{
return 1;
}
}
этот код работает нормально (насколько я знаю), но слишком медленно. Это занимает около 3 секунд, чтобы решить пример, и может быть 10000 чисел, чтобы сделать из 100 чисел.
3 ответов
У меня есть рекурсивное решение. Это решает оригинальную проблему OP примерно .005 секунд (на моей машине) и говорит вам расчеты.
private static readonly int Target = 1234567890;
private static readonly List<int> Parts = new List<int> { 4, 7, 18, 32, 57, 68 };
static void Main(string[] args)
{
Console.WriteLine(Solve(Target, Parts));
Console.ReadLine();
}
private static bool Solve(int target, List<int> parts)
{
parts.RemoveAll(x => x > target || x <= 0);
if (parts.Count == 0) return false;
var divisor = parts.First();
var quotient = target / divisor;
var modulus = target % divisor;
if (modulus == 0)
{
Console.WriteLine("{0} X {1}", quotient, divisor);
return true;
}
if (quotient == 0 || parts.Count == 1) return false;
while (!Solve(target - divisor * quotient, parts.Skip(1).ToList()))
{
if (--quotient != 0) continue;
return Solve(target, parts.Skip(1).ToList());
}
Console.WriteLine("{0} X {1}", quotient, divisor);
return true;
}
в основном, он проходит через каждое число, чтобы увидеть, есть ли возможное решение "ниже", учитывая текущее частное и число. Если нет, он вычитает 1 из частного и повторяет попытку. Он делает это до тех пор, пока не исчерпает все варианты для этого числа, а затем переходит к следующему номеру, если он доступен. Если все числа исчерпаны, решения нет.
не имеют средств проверить решение, но следующее должно сделать.
учитывая целевой номер target
и набор numbers
действительных чисел:
bool FindDecomposition(int target, IEnumerable<int> numbers, Queue<int> decomposition)
{
foreach (var i in numbers)
{
var remainder = target % i;
if (remainder == 0)
{
decomposition.Enqueue(i);
return true;
}
if (FindDecomposition(remainder, numbers.Where(n => n < i), decomposition))
{
return true;
}
}
return false
}
до здания n
С decomposition
- это довольно просто.
вы всегда можете попробовать использовать функцию по модулю в сочетании с выражениями LINQ для решения проблемы.
У вас будет список и работающая переменная по модулю, чтобы отслеживать, где вы находитесь в своей итерации. Затем просто используйте рекурсию, чтобы определить, соответствуете ли вы условиям.
одним из примеров может быть следующее:
static int toCreate = 1234567890;
static List<int> numbers = new List<int> { 4, 7 };
static void Main(string[] args)
{
numbers.Sort();
numbers.Reverse();
Console.WriteLine(Solve(numbers,toCreate).ToString());
}
static bool Solve(List<int> lst1, int runningModulo)
{
if (lst1.Count == 0 && runningModulo != 0)
return false;
if (lst1.Count == 0 || runningModulo == 0)
return true;
return numbers.Any(o => o < (toCreate % lst1.First())) ? //Are there any in the remaining list that are smaller in value than the runningModulo mod the first element in the list.
Solve(lst1.Where(o => o != lst1.First()).ToList(), runningModulo % lst1.First()) //If yes, then remove the first element and set the running modulo = to your new modulo
: Solve(lst1.Where(o => o != lst1.First()).ToList(), toCreate); //Otherwise, set the running modulo back to the original toCreate value.
}