Загрузка данных
#include <iostream>
#include <string>
#include <vector>
#include <set>
#include <map>
#include <iomanip>
using namespace std;
// Структура импликанты (куба)
struct Implicant {
string mask; // Маска, например: "01-1"
set<int> minterms; // Покрываемые минтермы: {1, 3}
bool combined = false; // Была ли склеена на текущем шаге
};
// 1. Перевод числа в двоичную строку фиксированной длины n
string numberToBinary(int num, int n) {
string binary = "";
for (int i = n - 1; i >= 0; --i) {
binary += ((num >> i) & 1) ? '1' : '0';
}
return binary;
}
// 2. Преобразование маски ("01-1") в буквенный вид ("xYZ")
string maskToVariables(const string& mask, int n) {
string term = "";
for (int i = 0; i < n; ++i) {
if (mask[i] == '-') continue;
// Для n <= 3 используем X, Y, Z; для n > 3 — A, B, C, D...
char upperVar = (n <= 3) ? ('X' + i) : ('A' + i);
char lowerVar = (n <= 3) ? ('x' + i) : ('a' + i);
term += (mask[i] == '1') ? upperVar : lowerVar;
}
return term.empty() ? "1" : term;
}
// 3. Форматированный вывод набора минтермов: {1, 3} -> "(1,3)"
string formatMinterms(const set<int>& minterms) {
string result = "(";
bool first = true;
for (int v : minterms) {
if (!first) result += ",";
result += to_string(v);
first = false;
}
result += ")";
return result;
}
// 4. Проверка возможности склейки двух импликант (различие ровно в 1 бит)
bool canCombine(const Implicant& a, const Implicant& b, int& diffIndex) {
int diffCount = 0;
diffIndex = -1;
for (size_t i = 0; i < a.mask.length(); ++i) {
if (a.mask[i] != b.mask[i]) {
diffCount++;
diffIndex = i;
}
}
return diffCount == 1;
}
// 5. Выделение минтермов (индексов единиц) из вектора значений
vector<int> extractMinterms(const string& truthTable) {
vector<int> minterms;
for (size_t i = 0; i < truthTable.length(); ++i) {
if (truthTable[i] == '1') {
minterms.push_back(static_cast<int>(i));
}
}
return minterms;
}
// 6. Пошаговая склейка кубов (0-мерные -> 1-мерные -> 2-мерные)
vector<Implicant> findPrimeImplicants(const vector<int>& minterms, int n) {
vector<Implicant> currentGroup;
for (int mt : minterms) {
currentGroup.push_back({numberToBinary(mt, n), {mt}, false});
}
vector<Implicant> primeImplicants;
int step = 0;
while (!currentGroup.empty()) {
cout << "-------------------------------------------------------\n";
cout << " Шаг склейки " << step << " (" << step << "-мерные кубы)\n";
cout << "-------------------------------------------------------\n";
for (const auto& imp : currentGroup) {
cout << setw(12) << left << formatMinterms(imp.minterms)
<< " : " << imp.mask << "\n";
}
cout << "\n";
vector<Implicant> nextGroup;
set<string> addedMasks;
for (size_t i = 0; i < currentGroup.size(); ++i) {
for (size_t j = i + 1; j < currentGroup.size(); ++j) {
int diffIndex = -1;
if (canCombine(currentGroup[i], currentGroup[j], diffIndex)) {
currentGroup[i].combined = true;
currentGroup[j].combined = true;
Implicant combinedImp;
combinedImp.mask = currentGroup[i].mask;
combinedImp.mask[diffIndex] = '-';
for (int mt : currentGroup[i].minterms) combinedImp.minterms.insert(mt);
for (int mt : currentGroup[j].minterms) combinedImp.minterms.insert(mt);
if (addedMasks.find(combinedImp.mask) == addedMasks.end()) {
addedMasks.insert(combinedImp.mask);
nextGroup.push_back(combinedImp);
cout << " Склейка: " << currentGroup[i].mask << " + "
<< currentGroup[j].mask << " -> " << combinedImp.mask
<< " для " << formatMinterms(combinedImp.minterms) << "\n";
}
}
}
}
// Сохраняем простые импликанты (те, что не удалось склеить дальше)
for (const auto& imp : currentGroup) {
if (!imp.combined) {
bool isDuplicate = false;
for (const auto& pi : primeImplicants) {
if (pi.mask == imp.mask) {
isDuplicate = true;
break;
}
}
if (!isDuplicate) {
primeImplicants.push_back(imp);
cout << " [*] Простая импликанта: " << imp.mask
<< " (" << maskToVariables(imp.mask, n) << ")\n";
}
}
}
currentGroup = nextGroup;
step++;
cout << "\n";
}
return primeImplicants;
}
// 7. Отрисовка таблицы покрытия (импликантной матрицы)
void printCoverageTable(const vector<Implicant>& primeImplicants, const vector<int>& minterms, int n) {
cout << "=======================================================\n";
cout << " ЭТАП 3: ИМПЛИКАНТНАЯ МАТРИЦА (ТАБЛИЦА ПОКРЫТИЯ)\n";
cout << "=======================================================\n\n";
cout << setw(18) << left << "Простая имплик." << " | ";
for (int mt : minterms) {
cout << setw(4) << mt;
}
int dashes = static_cast<int>(minterms.size()) * 4 + 1;
cout << "\n-------------------+" << string(dashes, '-') << "\n";
for (const auto& pi : primeImplicants) {
string label = maskToVariables(pi.mask, n) + " " + pi.mask;
cout << setw(18) << left << label << " | ";
for (int mt : minterms) {
if (pi.minterms.count(mt)) {
cout << " X "; // Вывод знака покрытия
} else {
cout << " ";
}
}
cout << "\n";
}
cout << "\n";
}
// 8. Поиск минимального покрытия (выбор оптимального набора импликант)
vector<Implicant> selectMinimalCover(const vector<Implicant>& primeImplicants, const vector<int>& minterms, int n) {
printCoverageTable(primeImplicants, minterms, n);
int p = static_cast<int>(primeImplicants.size());
vector<int> bestIndices;
int minLiterals = 1e9;
// Перебор всех комбинаций простых импликант
for (int mask = 1; mask < (1 << p); ++mask) {
set<int> coveredMinterms;
int currentLiterals = 0;
vector<int> currentIndices;
for (int i = 0; i < p; ++i) {
if ((mask >> i) & 1) {
currentIndices.push_back(i);
for (int mt : primeImplicants[i].minterms) {
coveredMinterms.insert(mt);
}
for (char c : primeImplicants[i].mask) {
if (c != '-') currentLiterals++;
}
}
}
if (coveredMinterms.size() == minterms.size()) {
if (currentLiterals < minLiterals ||
(currentLiterals == minLiterals && currentIndices.size() < bestIndices.size())) {
minLiterals = currentLiterals;
bestIndices = currentIndices;
}
}
}
vector<Implicant> minimalCover;
cout << "Выбранное минимальное покрытие:\n";
for (int idx : bestIndices) {
minimalCover.push_back(primeImplicants[idx]);
cout << " -> " << maskToVariables(primeImplicants[idx].mask, n)
<< " (" << primeImplicants[idx].mask << ") покрывает "
<< formatMinterms(primeImplicants[idx].minterms) << "\n";
}
return minimalCover;
}
// 9. Сборка итогового текстового выражения (ДНФ)
string buildDNF(const vector<Implicant>& cover, int n) {
string dnf = "";
for (size_t i = 0; i < cover.size(); ++i) {
if (i > 0) dnf += " v ";
dnf += maskToVariables(cover[i].mask, n);
}
return dnf;
}
// 10. Главная управляющая функция минимизации
string minimizeBooleanFunction(int n, const string& truthTable) {vector<int> minterms = extractMinterms(truthTable);
// Обработка константных функций
if (minterms.empty()) return "0";
if (minterms.size() == static_cast<size_t>(1 << n)) return "1";
cout << "\n=======================================================\n";
cout << " ЭТАП 1: ИСХОДНЫЕ МИНТЕРМЫ (0-МЕРНЫЕ КУБЫ)\n";
cout << "=======================================================\n";
cout << "Минтермы (единицы функции): ";
for (int mt : minterms) cout << mt << " ";
cout << "\n\n";
// Шаг 1-2: Нахождение всех простых импликант
vector<Implicant> primeImplicants = findPrimeImplicants(minterms, n);
cout << "=======================================================\n";
cout << " ЭТАП 2: ВСЕ ПРОСТЫЕ ИМПЛИКАНТЫ\n";
cout << "=======================================================\n";
for (const auto& pi : primeImplicants) {
cout << " - " << setw(8) << left << pi.mask
<< " -> " << setw(6) << left << maskToVariables(pi.mask, n)
<< " покрывает " << formatMinterms(pi.minterms) << "\n";
}
cout << "\n";
// Шаг 3: Выбор минимального покрытия
vector<Implicant> minimalCover = selectMinimalCover(primeImplicants, minterms, n);
// Шаг 4: Формирование строки результата
return buildDNF(minimalCover, n);
}
// =======================================================
// ЧИСТЫЙ MAIN
// =======================================================
int main() {
int n;
if (!(cin >> n)) return 0;
string truthTable;
cin >> truthTable;
// Запуск минимизации
string result = minimizeBooleanFunction(n, truthTable);
cout << "\n=======================================================\n";
cout << " ИТОГОВАЯ МИНИМАЛЬНАЯ ФОРМА (МинДНФ)\n";
cout << "=======================================================\n";
cout << "ВЫХОД: " << result << "\n\n";
return 0;
}