#include <iostream>
#include <vector>
#include <limits>
#include <iomanip>
#include <string>
#include <algorithm>
#include <set>
#include <map>
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};
}
void printCycle(const vector<pair<int, int>>& path) {
map<int, int> next;
for (auto [from, to] : path) next[from] = to;
set<int> visited;
for (auto [from, _] : path) {
if (visited.count(from)) continue;
int start = from;
cout << "Частковий цикл: ";
cout << char('A' + start);
visited.insert(start);
int curr = start;
while (next.count(curr) && next[curr] != start && !visited.count(next[curr])) {
curr = next[curr];
cout << " → " << char('A' + curr);
visited.insert(curr);
}
if (next.count(curr) && next[curr] == start)
cout << " → " << char('A' + start);
cout << endl;
}
}
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";
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 << "\n";
cout << "Редукция по столбцам: " << red2 << "\n";
cout << "Z = " << tempZ << " + " << red1 << " + " << red2 << " = " << Z << "\n";
cout << "Матрица после редукции:\n";
printMatrix(temp);
cout << "\nПоиск цикла на основе текущего пути:\n";
printCycle(path);
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];
printCycle(path);
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;
}