#include <iostream>
#include <vector>
#include <limits>
#include <iomanip>
#include <string>
#include <algorithm>
#include <set>
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 calculateUpperBound(const Matrix& mat) {
int total = 0;
vector<bool> visited(N, false);
int current = 0;
visited[current] = true;
for (int step = 1; step < N; ++step) {
int next = -1, minCost = INF;
for (int j = 0; j < N; ++j) {
if (!visited[j] && mat[current][j] < minCost) {
minCost = mat[current][j];
next = j;
}
}
if (next == -1) return INF;
total += minCost;
visited[next] = true;
current = next;
}
// Возвращение в начальную точку
total += mat[current][0];
return total;
}
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;
int totalCost = 0;
Matrix current = cost;
int level = 0;
while (path.size() < N) {
cout << "\nИтерация " << level + 1 << ":\n";
// Верхняя граница
int upperBound = calculateUpperBound(current);
cout << "Верхняя граница (жадная оценка): " << (upperBound >= INF ? -1 : upperBound) << "\n";
// Z до вычеркивания
int tempZ = totalCost;
Matrix temp = current;
int red1 = reduceRows(temp);
int red2 = reduceCols(temp);
int Z = totalCost + red1 + red2;
cout << "Z перед вычеркиванием: " << tempZ << "\n";
cout << "Редукция по строкам: " << red1 << ", по столбцам: " << red2 << "\n";
cout << "Z после редукции: " << Z << "\n";
cout << "Матрица после редукции:\n";
printMatrix(temp);
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];
// Обновляем матрицу: вычеркиваем строку 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;
}