#include <iostream>
#include <vector>
#include <limits>
#include <iomanip>
#include <string>
#include <algorithm>
using namespace std;
const int N = 5; // количество городов
const int INF = 1e6;
using Matrix = vector<vector<int>>;
void printMatrix(const Matrix& mat) {
for (int i = 0; i < N; ++i) {
for (int j = 0; j < N; ++j) {
if (mat[i][j] >= INF)
cout << "M ";
else
cout << setw(2) << mat[i][j] << " ";
}
cout << endl;
}
}
int reduceRows(Matrix& mat) {
int reduction = 0;
for (int i = 0; i < N; ++i) {
int rowMin = INF;
for (int j = 0; j < N; ++j)
rowMin = min(rowMin, mat[i][j]);
if (rowMin == INF) continue;
for (int j = 0; j < N; ++j)
if (mat[i][j] < INF) mat[i][j] -= rowMin;
reduction += rowMin;
}
return reduction;
}
int reduceCols(Matrix& mat) {
int reduction = 0;
for (int j = 0; j < N; ++j) {
int colMin = INF;
for (int i = 0; i < N; ++i)
colMin = min(colMin, mat[i][j]);
if (colMin == INF) continue;
for (int i = 0; i < N; ++i)
if (mat[i][j] < INF) mat[i][j] -= colMin;
reduction += colMin;
}
return reduction;
}
pair<int, pair<int, int>> selectNextEdge(const Matrix& mat) {
int maxPenalty = -1;
pair<int, int> bestEdge = {-1, -1};
for (int i = 0; i < N; ++i)
for (int j = 0; j < N; ++j)
if (mat[i][j] == 0) {
int rowMin = INF, colMin = INF;
for (int k = 0; k < N; ++k) {
if (k != j) rowMin = min(rowMin, mat[i][k]);
if (k != i) colMin = min(colMin, mat[k][j]);
}
int penalty = (rowMin == INF ? 0 : rowMin) + (colMin == INF ? 0 : colMin);
if (penalty > maxPenalty) {
maxPenalty = penalty;
bestEdge = {i, j};
}
}
return {maxPenalty, bestEdge};
}
int main() {
Matrix cost(N, vector<int>(N));
cout << "Введите матрицу " << N << "x" << N << " (используйте M для больших значений):\n";
for (int i = 0; i < N; ++i)
for (int j = 0; j < N; ++j) {
string s;
cin >> s;
if (s == "M" || s == "m")
cost[i][j] = INF;
else
cost[i][j] = stoi(s);
}
vector<pair<int, int>> path;
vector<vector<bool>> visited(N, vector<bool>(N, false));
int totalCost = 0;
Matrix current = cost;
int level = 0;
while (path.size() < N) {
cout << "\nИтерация " << level + 1 << ":\n";
Matrix temp = current;
int red1 = reduceRows(temp);
int red2 = reduceCols(temp);
int Z = totalCost + red1 + red2;
cout << "Матрица после редукции:\n";
printMatrix(temp);
cout << "Z = " << Z << " (накопленная нижняя граница)\n";
auto [penalty, edge] = selectNextEdge(temp);
int i = edge.first;
int j = edge.second;
if (i == -1 || j == -1) {
cout << "Нет подходящего ребра\n";
break;
}
cout << "Выбрана дуга: " << char('A' + i) << " → " << char('A' + j) << "\n";
path.push_back({i, j});
totalCost += cost[i][j];
// Обновляем матрицу
for (int k = 0; k < N; ++k) {
current[i][k] = INF;
current[k][j] = INF;
}
current[j][i] = INF;
level++;
}
cout << "\nОптимальный путь:\n";
for (auto [from, to] : path) {
cout << char('A' + from) << " → " << char('A' + to) << "\n";
}
cout << "Общая стоимость пути: " << totalCost << "\n";
return 0;
}