Логика. Логические функции. Решение уравнений
Программа на языке 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;
}
}
Вот как выглядят результаты решения по этой программе:
