Загрузка данных


#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;
}