Логика. Логические функции. Решение уравнений
Программа на языке C# для решения логических уравнений
Написать программу для решения логических уравнений полезно по многим причинам, хотя бы потому, что с ее помощью можно проверять правильность собственного решения тестовых задач ЕГЭ. Другая причина в том, что такая программа является прекрасным примером задачи на программирование, соответствующей требованиям, предъявляемым к задачам категории С в ЕГЭ.
Идея построения программы проста, - она основана на полном переборе всех возможных наборов значений переменных. Поскольку для заданного логического уравнения или системы уравнений число переменных n известно, то известно и число наборов – , которые требуется перебрать. Используя базовые функции языка C# - отрицание, дизъюнкцию, конъюнкцию и тождество, нетрудно написать программу, которая для заданного набора переменных вычисляет значение логической функции, соответствующей логическому уравнению или системе уравнений.
В такой программе нужно построить цикл по числу наборов, в теле цикла по номеру набора сформировать сам набор, вычислить значение функции на этом наборе, и если это значение равно 1, то набор дает решение уравнения.
Единственная сложность, возникающая при реализации программы, связана с задачей формирования по номеру набора самого набора значений переменных. Красота этой задачи в том, что эта, казалось бы, трудная задача, фактически сводится к простой, уже неоднократно возникавшей задаче. Действительно, достаточно понять, что соответствующий числу i набор значений переменных, состоящий из нулей и единиц, представляет двоичную запись числа i. Так что сложная задача получения набора значений переменных по номеру набора сводится к хорошо знакомой задаче перевода числа в двоичную систему.
Вот как выглядит функция на языке C#, решающая нашу задачу:
/// <summary> /// программа подсчета числа решений /// логического уравнения (системы уравнений) /// </summary> /// <param name="fun"> /// логическая функция - метод, /// сигнатура которого задается делегатом DF /// </param> /// <param name="n">число переменных</param> /// <returns> число решений</returns> static int SolveEquations(DF fun, int n) { int res = 0; bool[] set = new bool[n]; int m = (int)Math.Pow(2, n); //число наборов int p = 0, q = 0, k = 0; //Полный перебор по числу наборов for (int i = 0; i < m; i++) { p = i; //Формирование очередного набора - set, //заданного двоичным представлением числа i for (int j = 0; j < n; j++) { k = (int)Math.Pow(2, j); q = p % 2; p = p / 2; if (q == 0) set[j] = false; else set[j] = true; } //Вычисление значения функции на наборе set if(fun(set)) res ++; } return res; }
Для понимания программы, надеюсь, достаточно сделанных объяснений идеи программы и комментариев в ее тексте. Остановлюсь лишь на пояснении заголовка приведенной функции. У функции SolveEquations два входных параметра. Параметр fun задает логическую функцию, соответствующую решаемому уравнению или системе уравнений. Параметр n задает число переменных функции fun. В качестве результата функция SolveEquations возвращает число решений логической функции, то есть число тех наборов, на которых функция принимает значение true.
Для школьников привычно, когда у некоторой функции F(x) входным параметром x является переменная арифметического, строкового или логического типа. В нашем случае используется более мощная конструкция. Функция SolveEquations относится к функциям высшего порядка – функциям типа F(f), у которых параметрами могут быть не только простые переменные, но и функции.
Класс функций, которые могут передаваться в качестве параметра функции SolveEquations, задается следующим образом:
delegate bool DF(bool[] vars);
Этому классу принадлежат все функции, которым в качестве параметра передается набор значений логических переменных, заданных массивом vars. В качестве результата возвращается значение булевского типа, представляющее значение функции на этом наборе.
В заключение приведу программу, в которой функция SolveEquations используется для решения нескольких систем логических уравнений. Функция SolveEquations является частью приводимого ниже класса ProgramCommon:
class ProgramCommon { delegate bool DF(bool[] vars); static void Main(string[] args) { Console.WriteLine("У Функции And решений - " + SolveEquations(FunAnd, 2)); Console.WriteLine("У Функции 51 решений - " + SolveEquations(Fun51, 5)); Console.WriteLine("У Функции 53 решений - " + SolveEquations(Fun53, 10)); } static bool FunAnd(bool[] vars) { return vars[0] && vars[1]; } static bool Fun51(bool[] vars) { bool f = true; f = f && (!vars[0] || vars[1]); f = f && (!vars[2] || vars[1]); f = f && (!vars[3] || vars[4]); f = f && (!vars[1] || vars[3]); f = f && (!vars[3] || vars[2]); return f; } static bool Fun53(bool[] vars) { bool f = true; f = f && ((vars[0] == vars[1]) || (vars[0] == vars[2])); f = f && ((vars[1] == vars[2]) || (vars[1] == vars[3])); f = f && ((vars[2] == vars[3]) || (vars[2] == vars[4])); f = f && ((vars[3] == vars[4]) || (vars[3] == vars[5])); f = f && ((vars[4] == vars[5]) || (vars[4] == vars[6])); f = f && ((vars[5] == vars[6]) || (vars[5] == vars[7])); f = f && ((vars[6] == vars[7]) || (vars[6] == vars[8])); f = f && (!((vars[7] == vars[8]) || (vars[7] == vars[9]))); return f; } }
Вот как выглядят результаты решения по этой программе: