В практике программиста 1С часто встречаются задачи, требующие не только знания встроенного языка, но и умения применять алгоритмические методы для проверки логических гипотез. Одной из таких классических задач является головоломка: расставить знаки плюс, минус, умножение и деление ровно по одному разу между пятью пятерками так, чтобы в результате получилось 20. При этом количество скобок не ограничено.
В рамках данной статьи мы не просто попытаемся найти ответ, а разберем по шагам, как с помощью платформы 1С доказать наличие или отсутствие решения, проанализируем математические ограничения и рассмотрим альтернативные подходы к решению подобных задач «с подвохом».
Прежде чем приступать к написанию кода, давайте проанализируем условия. У нас есть пять цифр 5 и четыре обязательных оператора: +, -, *, /. Каждый оператор должен быть использован строго один раз. Это существенно сужает пространство поиска, так как мы не можем заменить «неудобный» оператор деления на второй плюс или минус.
С точки зрения математики начальной школы, задача кажется простой, однако при глубоком анализе выясняется следующее:
(5 * 5) - 5 + (5 / 5) = 21.Для того чтобы окончательно убедиться в возможности решения, проанализируем ситуацию программно. Самый надежный способ — это полный перебор (brute force) всех возможных комбинаций знаков и расстановок скобок. В 1С для вычисления строковых выражений идеально подходит функция Вычислить().
Рассмотрим структуру алгоритма. Нам необходимо:
Ниже представлен пример кода, который выполняет перебор базовых вариантов расстановки знаков без учета всех возможных вложений скобок (для упрощения понимания):
Процедура ВыполнитьПеребор()
Знаки = Новый Массив;
Знаки.Добавить("+");
Знаки.Добавить("-");
Знаки.Добавить("*");
Знаки.Добавить("/");
// Используем упрощенный перебор перестановок знаков
Для каждого Зн1 Из Знаки Цикл
Для каждого Зн2 Из Знаки Цикл
Если Зн2 = Зн1 Тогда Продолжить; КонецЕсли;
Для каждого Зн3 Из Знаки Цикл
Если Зн3 = Зн1 Или Зн3 = Зн2 Тогда Продолжить; КонецЕсли;
Для каждого Зн4 Из Знаки Цикл
Если Зн4 = Зн1 Или Зн4 = Зн2 Или Зн4 = Зн3 Тогда Продолжить; КонецЕсли;
// Формируем выражение без скобок
Выражение = "5" + Зн1 + "5" + Зн2 + "5" + Зн3 + "5" + Зн4 + "5";
ПроверитьРезультат(Выражение);
// Примеры шаблонов со скобками
ПроверитьРезультат("(5" + Зн1 + "5)" + Зн2 + "(5" + Зн3 + "5)" + Зн4 + "5");
ПроверитьРезультат("((5" + Зн1 + "5)" + Зн2 + "5)" + Зн3 + "5" + Зн4 + "5");
// ... и так далее для всех типов скобок
КонецЦикла;
КонецЦикла;
КонецЦикла;
КонецЦикла;
КонецПроцедуры
Процедура ПроверитьРезультат(ТекстВыражения)
Попытка
Результат = Вычислить(ТекстВыражения);
Если Результат = 20 Тогда
Сообщить("Найдено решение: " + ТекстВыражения);
КонецЕсли;
Исключение
// Игнорируем деление на ноль
КонецПопытки;
КонецПроцедуры
После запуска полноценного скрипта перебора, учитывающего все возможные расстановки скобок (а их для пяти операндов существует 14 основных структур, описываемых числами Каталана), программисты приходят к выводу: в десятичной системе счисления при использовании знаков +, -, *, / ровно по одному разу получить 20 невозможно.
Это типичная «ловушка» для учеников и их родителей. Однако в математических кружках и на форумах часто предлагают решения, которые «взламывают» условия задачи.
Если мы рассмотрим подробнее варианты, выходящие за рамки стандартной арифметики 4 класса, можно выделить несколько интересных путей:
1. Визуальное решение (логический трюк)
Некоторые педагоги принимают ответ, основанный на визуальном представлении чисел. Если составить выражение (5 + 5 / 5), что дает 2, и (5 - 5), что дает 0, и записать их результаты рядом, получится число «20». Но с точки зрения строгого математического вычисления это некорректно.
2. Использование других систем счисления
В ходе обсуждения на форуме было предложено оригинальное решение для восьмеричной системы счисления:
5 * 5 + (-55) / 5 = 20 (в системе счисления по основанию 8)
Давайте выясним причину, почему это работает. В восьмеричной системе:
5 * 5 = 31 (так как 25 в десятичной — это 3*8 + 1)55 / 5 = 1131 - 11 = 20Однако вряд ли от четвероклассника ожидают знания систем счисления.
3. Неявное умножение и склеивание цифр
Если допустить, что знак умножения перед скобкой можно опускать (что иногда встречается в продвинутых программах), появляются варианты типа 5 / 5 * (-5 + 5 * 5), но здесь нарушается правило использования каждого знака ровно один раз.
Вычислить() в 1СПри решении подобных задач или реализации калькуляторов в среде 1С, проанализируем важные моменты работы с функцией Вычислить():
Попытка...Исключение. При переборе вы неизбежно столкнетесь с делением на ноль.Вычислить() работает в контексте того модуля, где она вызвана.Мы проанализировали ситуацию и пришли к выводу, что задача о пяти пятерках в ее строгой постановке не имеет решения в области целых чисел десятичной системы. Это отличный пример того, как программирование помогает быстро верифицировать математические гипотезы и экономить время на поиске несуществующих ответов. Если вы столкнулись с такой задачей в учебнике ребенка, скорее всего, там допущена опечатка (например, должно быть четыре пятерки), либо это задача на доказательство невозможности решения.