Загрузка данных
#include <iostream>
#include <conio.h>
#include <chrono>
#include <cmath>
#include <ctime>
#include <vector>
#include <limits>
#include <iomanip>
#include <algorithm>
using namespace std;
using namespace std::chrono;
// ============================================================
// СТРУКТУРЫ И КЛАССЫ (глобальные)
// ============================================================
// Edge structure
struct Edge {
long long u, v, weight;
Edge(long long _u, long long _v, long long _w) : u(_u), v(_v), weight(_w) {}
bool operator<(const Edge& other) const {
return weight < other.weight;
}
};
// DSU (Disjoint Set Union)
class DSU {
private:
vector<long long> parent, rank;
public:
DSU(long long n) {
parent.resize(n + 1);
rank.resize(n + 1, 0);
for (long long i = 1; i <= n; i++) parent[i] = i;
}
long long find(long long x) {
if (parent[x] != x)
parent[x] = find(parent[x]);
return parent[x];
}
bool unite(long long x, long long y) {
long long rx = find(x), ry = find(y);
if (rx == ry) return false;
if (rank[rx] < rank[ry]) swap(rx, ry);
parent[ry] = rx;
if (rank[rx] == rank[ry]) rank[rx]++;
return true;
}
};
// ============================================================
// ПРОТОТИПЫ ФУНКЦИЙ
// ============================================================
// Сортировки
void selectionSort();
void bubbleSort();
void insertionSort();
void binaryInsertionSort();
void mergeSort();
void quickSort();
// Вспомогательные функции для Merge Sort
void mergeOptimized(vector<int>& arr, vector<int>& temp, long long left, long long mid, long long right);
void mergeSortRecursiveOpt(vector<int>& arr, vector<int>& temp, long long left, long long right);
// Вспомогательные функции для Quick Sort
long long partition(vector<int>& arr, long long low, long long high);
void quickSortRecursive(vector<int>& arr, long long low, long long high);
// Поиск и задачи
void sequentialSearch();
void closestPairPoints();
void checkUniqueness();
// Динамическое программирование
void binomialCoefficient();
void warshallAlgorithm();
void floydAlgorithm();
// Математика (НОД)
void gcdComparison();
// Утилиты
long long getArraySize();
long long getGraphSize();
void showMenu();
// Graph data functions
vector<Edge> getKonkovoGraph();
vector<Edge> getArbatGraph();
void printKonkovoVertices();
void printArbatVertices();
void printAdjacencyTable(long long n, const vector<Edge>& edges);
// Kruskal algorithm
bool dfsPath(long long cur, long long target, const vector<vector<pair<long long, long long>>>& adj,
vector<bool>& visited, vector<long long>& path);
void kruskalShortestPath();
// ============================================================
// ГЛАВНАЯ ФУНКЦИЯ (MAIN)
// ============================================================
int main() {
srand(time(0)); // Инициализация генератора случайных чисел
char ch;
// Бесконечный цикл меню
do {
showMenu();
ch = _getch(); // Считываем нажатие клавиши
cout << ch << "\n";
switch (ch) {
case '1': selectionSort(); break;
case '2': bubbleSort(); break;
case '3': sequentialSearch(); break;
case '4': closestPairPoints(); break;
case '5': checkUniqueness(); break;
case '6': gcdComparison(); break;
case '7': insertionSort(); break;
case '8': binaryInsertionSort(); break;
case '9': mergeSort(); break;
case 'a': quickSort(); break;
case 'b': binomialCoefficient(); break;
case 'c': warshallAlgorithm(); break;
case 'd': floydAlgorithm(); break;
case 'e': kruskalShortestPath(); break;
case '0': cout << "Завершение программы...\n"; break;
default: cout << "Неверный выбор! Нажмите любую клавишу..."; _getch();
}
// Пауза перед возвратом в меню (кроме выхода)
if (ch != '0') {
cout << "\nНажмите любую клавишу для продолжения...";
_getch();
}
} while (ch != '0');
return 0;
}
// ============================================================
// ФУНКЦИЯ МЕНЮ
// ============================================================
void showMenu() {
cout << "\n============ МЕНЮ ===========\n";
cout << "1. Сортировка выбором\n";
cout << "2. Пузырьковая сортировка\n";
cout << "3. Последовательный поиск\n";
cout << "4. Поиск ближайших точек\n";
cout << "5. Проверка уникальности элементов\n";
cout << "6. Сравнение алгоритмов НОД\n";
cout << "7. Сортировка вставками\n";
cout << "8. Бинарная сортировка вставками\n";
cout << "9. Сортировка слиянием (оптимизированная)\n";
cout << "a. Быстрая сортировка (Quick Sort)\n";
cout << "b. Вычисление биномиальных коэффициентов\n";
cout << "c. Алгоритм Воршалла (транзитивное замыкание)\n";
cout << "d. Алгоритм Флойда (кратчайшие пути для всех пар)\n";
cout << "e. Алгоритм Крускала + поиск пути в остовном дереве\n";
cout << "0. Выход из программы\n";
cout << "==========================\n";
cout << "Выберите пункт меню: ";
}
// ============================================================
// ПОЛУЧЕНИЕ РАЗМЕРА МАССИВА
// ============================================================
long long getArraySize() {
int choice;
cout << "\nВыберите размер массива:\n";
cout << "1. Малый размер (x < 100)\n";
cout << "2. Средний размер (100 < x < 10 000)\n";
cout << "3. Большой размер (10 000 < x < 1 000 000)\n";
cout << "4. Ввести размер вручную (точное число)\n";
cout << "Ваш выбор: ";
cin >> choice;
long long size;
switch (choice) {
case 1: size = rand() % 100 + 10; break;
case 2: size = rand() % 9900 + 100; break;
case 3: size = rand() % 990000 + 10000; break;
case 4:
cout << "Введите размер массива (положительное целое число): ";
cin >> size;
if (size < 1) size = 1;
break;
default: cout << "Неверный выбор, используется размер по умолчанию: 100.\n"; size = 100;
}
cout << "Размер массива: " << size << "\n";
return size;
}
// ============================================================
// ПОЛУЧЕНИЕ РАЗМЕРА ГРАФА (для алгоритмов Воршалла и Флойда)
// ============================================================
long long getGraphSize() {
int choice;
cout << "\nВыберите количество вершин графа:\n";
cout << "1. Малое количество (x < 100)\n";
cout << "2. Среднее количество (100 < x < 1 000)\n";
cout << "3. Большое количество (1 000 < x < 10 000)\n";
cout << "4. Очень большое количество (10 000 < x < 100 000)\n";
cout << "5. Ввести количество вручную (точное число)\n";
cout << "Ваш выбор: ";
cin >> choice;
long long size;
switch (choice) {
case 1: size = rand() % 100 + 10; break;
case 2: size = rand() % 900 + 100; break;
case 3: size = rand() % 9000 + 1000; break;
case 4: size = rand() % 90000 + 10000; break;
case 5:
cout << "Введите количество вершин (положительное целое число): ";
cin >> size;
if (size < 1) size = 1;
break;
default: cout << "Неверный выбор, используется значение по умолчанию: 50.\n"; size = 50;
}
cout << "Количество вершин: " << size << "\n";
return size;
}
// ============================================================
// 1. SELECTION SORT (Сортировка выбором)
// ============================================================
void selectionSort() {
cout << "\n=== СОРТИРОВКА ВЫБОРОМ ====\n";
long long n = getArraySize();
vector<int> arr(n);
for (long long i = 0; i < n; i++) arr[i] = rand() % 10000;
auto start = high_resolution_clock::now();
for (long long i = 0; i < n - 1; i++) {
long long min_idx = i;
for (long long j = i + 1; j < n; j++) {
if (arr[j] < arr[min_idx]) min_idx = j;
}
if (min_idx != i) swap(arr[i], arr[min_idx]);
}
auto stop = high_resolution_clock::now();
auto duration = duration_cast<microseconds>(stop - start);
cout << "Массив отсортирован!\n";
cout << "Время выполнения: " << duration.count() << " микросекунд\n";
cout << "Первые 10 элементов: ";
for (int i = 0; i < min(10LL, n); i++) cout << arr[i] << " ";
cout << "\n";
}
// ============================================================
// 2. BUBBLE SORT (Пузырьковая сортировка)
// ============================================================
void bubbleSort() {
cout << "\n=== ПУЗЫРЬКОВАЯ СОРТИРОВКА ===\n";
long long n = getArraySize();
vector<int> arr(n);
for (long long i = 0; i < n; i++) arr[i] = rand() % 10000;
auto start = high_resolution_clock::now();
for (long long i = 0; i < n - 1; i++) {
for (long long j = 0; j < n - i - 1; j++) {
if (arr[j] > arr[j + 1]) swap(arr[j], arr[j + 1]);
}
}
auto stop = high_resolution_clock::now();
auto duration = duration_cast<microseconds>(stop - start);
cout << "Массив отсортирован!\n";
cout << "Время выполнения: " << duration.count() << " микросекунд\n";
cout << "Первые 10 элементов: ";
for (int i = 0; i < min(10LL, n); i++) cout << arr[i] << " ";
cout << "\n";
}
// ============================================================
// 3. SEQUENTIAL SEARCH (Последовательный поиск)
// ============================================================
void sequentialSearch() {
cout << "\n=== ПОСЛЕДОВАТЕЛЬНЫЙ ПОИСК ===\n";
long long n = getArraySize();
vector<int> arr(n);
for (long long i = 0; i < n; i++) arr[i] = rand() % 10000;
int keyChoice;
cout << "\nВыберите тип искомого элемента:\n";
cout << "1. Ввести ключ вручную (может отсутствовать в массиве)\n";
cout << "2. Использовать ключ, который ТОЧНО есть в массиве\n";
cout << "Ваш выбор: ";
cin >> keyChoice;
int key;
if (keyChoice == 2) {
long long randomIndex = rand() % n;
key = arr[randomIndex];
cout << "Искомый ключ (из массива): " << key << " (на позиции " << randomIndex << ")\n";
}
else {
cout << "Введите искомый ключ: ";
cin >> key;
}
volatile long long foundIndex = -1;
auto start = high_resolution_clock::now();
for (long long i = 0; i < n; i++) {
if (arr[i] == key) { foundIndex = i; break; }
}
auto stop = high_resolution_clock::now();
auto duration = duration_cast<microseconds>(stop - start);
cout << "\n--- Результаты ---\n";
if (foundIndex != -1) cout << "Элемент найден на позиции: " << foundIndex << "\n";
else cout << "Элемент не найден\n";
cout << "Время выполнения: " << duration.count() << " микросекунд\n";
cout << "Первые 10 элементов: ";
for (int i = 0; i < min(10LL, n); i++) cout << arr[i] << " ";
cout << "\n";
}
// ============================================================
// 4. CLOSEST PAIR OF POINTS (Поиск ближайших точек)
// ============================================================
void closestPairPoints() {
cout << "\n=== ПОИСК БЛИЖАЙШЕЙ ПАРЫ ТОЧЕК ===\n";
long long n = getArraySize();
vector<pair<double, double>> points(n);
for (long long i = 0; i < n; i++) {
points[i].first = (double)(rand() % 10000) / 100.0;
points[i].second = (double)(rand() % 10000) / 100.0;
}
auto start = high_resolution_clock::now();
double minDist = numeric_limits<double>::max();
long long idx1 = 0, idx2 = 1;
for (long long i = 0; i < n - 1; i++) {
for (long long j = i + 1; j < n; j++) {
double dx = points[i].first - points[j].first;
double dy = points[i].second - points[j].second;
double dist = sqrt(dx * dx + dy * dy);
if (dist < minDist) { minDist = dist; idx1 = i; idx2 = j; }
}
}
auto stop = high_resolution_clock::now();
auto duration = duration_cast<microseconds>(stop - start);
cout << "Ближайшие точки:\n";
cout << "Точка 1: (" << points[idx1].first << ", " << points[idx1].second << ")\n";
cout << "Точка 2: (" << points[idx2].first << ", " << points[idx2].second << ")\n";
cout << "Расстояние: " << minDist << "\n";
cout << "Время выполнения: " << duration.count() << " микросекунд\n";
}
// ============================================================
// 5. CHECK UNIQUENESS (Проверка уникальности)
// ============================================================
void checkUniqueness() {
cout << "\n=== ПРОВЕРКА УНИКАЛЬНОСТИ ЭЛЕМЕНТОВ ====\n";
long long n = getArraySize();
vector<double> arr(n);
for (long long i = 0; i < n; i++) arr[i] = (double)(rand() % 10000) / 100.0;
auto start = high_resolution_clock::now();
bool isUnique = true;
for (long long i = 0; i < n - 1; i++) {
for (long long j = i + 1; j < n; j++) {
if (arr[i] == arr[j]) {
isUnique = false;
goto end_check;
}
}
}
end_check:
auto stop = high_resolution_clock::now();
auto duration = duration_cast<microseconds>(stop - start);
if (isUnique) cout << "Результат: Все элементы УНИКАЛЬНЫ\n";
else cout << "Результат: Массив содержит ПОВТОРЯЮЩИЕСЯ элементы \n";
cout << "Время выполнения: " << duration.count() << " микросекунд\n";
cout << "Первые 10 элементов: ";
for (int i = 0; i < min(10LL, n); i++) cout << fixed << setprecision(2) << arr[i] << " ";
cout << "\n";
}
// ============================================================
// 6. GCD COMPARISON (Сравнение алгоритмов НОД)
// ============================================================
void gcdComparison() {
int m, n;
cout << "Введите m: "; cin >> m; cout << endl;
cout << "Введите n: "; cin >> n; cout << endl;
int m1 = m, n1 = n, i1 = 0, i2 = 0;
while (m1 != n1) {
if (m1 > n1) m1 -= n1; else n1 -= m1;
i1++;
}
cout << "Метод 1 (вычитание): НОД = " << m1 << ", итераций: " << i1;
cout << endl << endl;
while (m != 0 && n != 0) {
if (m > n) m %= n; else n %= m;
i2++;
}
cout << "Метод 2 (деление с остатком): НОД = " << (m + n) << ", итераций: " << i2;
cout << endl << endl;
if (i2 < i1) cout << "\nПервый алгоритм быстрее на " << (i1 - i2) << " итераций";
else if (i2 > i1) cout << "\nВторой алгоритм быстрее на " << (i2 - i1) << " итераций";
else cout << "\nАлгоритмы показали одинаковую скорость";
cout << endl << endl;
system("pause");
}
// ============================================================
// 7. INSERTION SORT (Сортировка вставками)
// ============================================================
void insertionSort() {
cout << "\n=== СОРТИРОВКА ВСТАВКАМИ ===\n";
long long n = getArraySize();
vector<int> arr(n);
for (long long i = 0; i < n; i++) arr[i] = rand() % 10000;
auto start = high_resolution_clock::now();
for (long long i = 1; i < n; i++) {
int key = arr[i];
long long j = i - 1;
while (j >= 0 && arr[j] > key) {
arr[j + 1] = arr[j];
j--;
}
arr[j + 1] = key;
}
auto stop = high_resolution_clock::now();
auto duration = duration_cast<microseconds>(stop - start);
cout << "Массив отсортирован!\n";
cout << "Время выполнения: " << duration.count() << " микросекунд\n";
cout << "Первые 10 элементов: ";
for (int i = 0; i < min(10LL, n); i++) cout << arr[i] << " ";
cout << "\n";
}
// ============================================================
// 8. BINARY INSERTION SORT (Бинарная сортировка вставками)
// ============================================================
void binaryInsertionSort() {
cout << "\n=== БИНАРНАЯ СОРТИРОВКА ВСТАВКАМИ ===\n";
long long n = getArraySize();
vector<int> arr(n);
for (long long i = 0; i < n; i++) arr[i] = rand() % 10000;
auto start = high_resolution_clock::now();
for (long long i = 1; i < n; i++) {
int key = arr[i];
long long left = 0, right = i;
while (left < right) {
long long mid = left + (right - left) / 2;
if (arr[mid] < key) {
left = mid + 1;
}
else {
right = mid;
}
}
for (long long j = i - 1; j >= left; j--) {
arr[j + 1] = arr[j];
}
arr[left] = key;
}
auto stop = high_resolution_clock::now();
auto duration = duration_cast<microseconds>(stop - start);
cout << "Массив отсортирован!\n";
cout << "Время выполнения: " << duration.count() << " микросекунд\n";
cout << "Первые 10 элементов: ";
for (int i = 0; i < min(10LL, n); i++) cout << arr[i] << " ";
cout << "\n";
}
// ============================================================
// 9. MERGE SORT (Оптимизированная сортировка слиянием)
// ============================================================
void mergeOptimized(vector<int>& arr, vector<int>& temp, long long left, long long mid, long long right) {
long long i = left, j = mid + 1, k = left;
for (long long idx = left; idx <= right; idx++) temp[idx] = arr[idx];
while (i <= mid && j <= right) {
if (temp[i] <= temp[j]) arr[k++] = temp[i++];
else arr[k++] = temp[j++];
}
while (i <= mid) arr[k++] = temp[i++];
}
void mergeSortRecursiveOpt(vector<int>& arr, vector<int>& temp, long long left, long long right) {
if (left < right) {
long long mid = left + (right - left) / 2;
mergeSortRecursiveOpt(arr, temp, left, mid);
mergeSortRecursiveOpt(arr, temp, mid + 1, right);
mergeOptimized(arr, temp, left, mid, right);
}
}
void mergeSort() {
cout << "\n=== СОРТИРОВКА СЛИЯНИЕМ (ОПТИМИЗИРОВАННАЯ) ===\n";
long long n = getArraySize();
vector<int> arr(n);
for (long long i = 0; i < n; i++) arr[i] = rand() % 10000;
vector<int> temp(n);
auto start = high_resolution_clock::now();
mergeSortRecursiveOpt(arr, temp, 0, n - 1);
auto stop = high_resolution_clock::now();
auto duration = duration_cast<microseconds>(stop - start);
cout << "Массив отсортирован!\n";
cout << "Время выполнения: " << duration.count() << " микросекунд!\n";
cout << "Первые 10 элементов: ";
for (int i = 0; i < min(10LL, n); i++) cout << arr[i] << " ";
cout << "\n";
}
// ============================================================
// 10. QUICK SORT (Быстрая сортировка)
// ============================================================
long long partition(vector<int>& arr, long long low, long long high) {
int pivot = arr[high];
long long i = low - 1;
for (long long j = low; j < high; j++) {
if (arr[j] <= pivot) {
i++;
swap(arr[i], arr[j]);
}
}
swap(arr[i + 1], arr[high]);
return i + 1;
}
void quickSortRecursive(vector<int>& arr, long long low, long long high) {
if (low < high) {
long long pi = partition(arr, low, high);
quickSortRecursive(arr, low, pi - 1);
quickSortRecursive(arr, pi + 1, high);
}
}
void quickSort() {
cout << "\n=== БЫСТРАЯ СОРТИРОВКА (QUICK SORT) ===\n";
long long n = getArraySize();
vector<int> arr(n);
for (long long i = 0; i < n; i++) arr[i] = rand() % 10000;
auto start = high_resolution_clock::now();
quickSortRecursive(arr, 0, n - 1);
auto stop = high_resolution_clock::now();
auto duration = duration_cast<microseconds>(stop - start);
cout << "Массив отсортирован!\n";
cout << "Время выполнения: " << duration.count() << " микросекунд\n";
cout << "Первые 10 элементов: ";
for (int i = 0; i < min(10LL, n); i++) cout << arr[i] << " ";
cout << "\n";
}
// ============================================================
// 11. BINOMIAL COEFFICIENT (Биномиальные коэффициенты)
// ============================================================
long long binomial(int n, int k) {
if (k < 0 || k > n) return 0;
if (k == 0 || k == n) return 1;
if (k > n - k) k = n - k;
vector<vector<long long>> C(n + 1, vector<long long>(k + 1, 0));
for (int i = 0; i <= n; i++) {
for (int j = 0; j <= min(i, k); j++) {
if (j == 0 || j == i) C[i][j] = 1;
else C[i][j] = C[i - 1][j - 1] + C[i - 1][j];
}
}
return C[n][k];
}
void binomialCoefficient() {
cout << "\n=== ВЫЧИСЛЕНИЕ БИНОМИАЛЬНЫХ КОЭФФИЦИЕНТОВ ===\n";
int choice;
cout << "\nВыберите способ задания n и k:\n";
cout << "1. Случайные числа (x < 100)\n";
cout << "2. Случайные числа (100 < x < 1 000)\n";
cout << "3. Случайные числа (1 000 < x < 10 000)\n";
cout << "4. Случайные числа (10 000 < x < 100 000)\n";
cout << "5. Ввести значения вручную\n";
cout << "Ваш выбор: ";
cin >> choice;
int n, k;
if (choice == 5) {
cout << "Введите n: ";
cin >> n;
cout << "Введите k (0 <= k <= n): ";
cin >> k;
if (k < 0 || k > n) {
cout << "Ошибка: k должно быть в диапазоне [0, n]\n";
return;
}
}
else {
long long maxVal;
switch (choice) {
case 1: maxVal = rand() % 100; break;
case 2: maxVal = rand() % 900 + 100; break;
case 3: maxVal = rand() % 9000 + 1000; break;
case 4: maxVal = rand() % 90000 + 10000; break;
default: maxVal = 50;
}
n = maxVal;
k = rand() % (n + 1);
}
cout << "\nСгенерированные значения: n = " << n << ", k = " << k << "\n";
if (n > 60) {
cout << "Предупреждение: при n > 60 результат может переполнить тип long long.\n";
}
auto start = high_resolution_clock::now();
long long result = binomial(n, k);
auto stop = high_resolution_clock::now();
auto duration = duration_cast<microseconds>(stop - start);
cout << "\nC(" << n << ", " << k << ") = " << result << "\n";
cout << "Время выполнения: " << duration.count() << " микросекунд\n";
if (n <= 20) {
cout << "\nСтрока треугольника Паскаля для n = " << n << ":\n";
for (int i = 0; i <= n; i++) {
cout << binomial(n, i) << " ";
}
cout << "\n";
}
else {
cout << "\n(Вывод строки треугольника Паскаля пропущен для n > 20)\n";
}
}
// ============================================================
// 12. WARSHALL ALGORITHM (Алгоритм Воршалла)
// ============================================================
void warshallAlgorithm() {
cout << "\n=== АЛГОРИТМ ВОРШАЛЛА (ТРАНЗИТИВНОЕ ЗАМЫКАНИЕ) ===\n";
long long n = getGraphSize();
// Создаём случайную матрицу смежности
vector<vector<int>> R(n, vector<int>(n, 0));
for (long long i = 0; i < n; i++) {
R[i][i] = 1;
for (long long j = 0; j < n; j++) {
if (i != j && rand() % 3 == 0) {
R[i][j] = 1;
}
}
}
auto start = high_resolution_clock::now();
for (long long k = 0; k < n; k++) {
for (long long i = 0; i < n; i++) {
if (R[i][k] == 0) continue;
for (long long j = 0; j < n; j++) {
if (R[k][j] == 1) {
R[i][j] = 1;
}
}
}
}
auto stop = high_resolution_clock::now();
auto duration = duration_cast<microseconds>(stop - start);
cout << "Время выполнения: " << duration.count() << " микросекунд\n";
}
// ============================================================
// 13. FLOYD ALGORITHM (Алгоритм Флойда)
// ============================================================
void floydAlgorithm() {
cout << "\n=== АЛГОРИТМ ФЛОЙДА (КРАТЧАЙШИЕ ПУТИ ДЛЯ ВСЕХ ПАР ВЕРШИН) ===\n";
long long n = getGraphSize();
const int INF = 1000000;
vector<vector<int>> D(n, vector<int>(n, INF));
for (long long i = 0; i < n; i++) {
D[i][i] = 0;
for (long long j = 0; j < n; j++) {
if (i != j && rand() % 4 == 0) {
D[i][j] = rand() % 100 + 1;
}
}
}
auto start = high_resolution_clock::now();
for (long long k = 0; k < n; k++) {
for (long long i = 0; i < n; i++) {
for (long long j = 0; j < n; j++) {
if (D[i][k] < INF && D[k][j] < INF) {
D[i][j] = min(D[i][j], D[i][k] + D[k][j]);
}
}
}
}
auto stop = high_resolution_clock::now();
auto duration = duration_cast<microseconds>(stop - start);
long long reachable = 0;
long long totalDist = 0;
for (long long i = 0; i < n; i++) {
for (long long j = 0; j < n; j++) {
if (i != j && D[i][j] < INF) {
reachable++;
totalDist += D[i][j];
}
}
}
cout << "Кратчайшие пути вычислены!\n";
cout << "Достижимых пар вершин: " << reachable << " из " << (n * (n - 1)) << "\n";
if (reachable > 0) {
cout << "Средняя длина пути: " << fixed << setprecision(2) << (double)totalDist / reachable << "\n";
}
cout << "Время выполнения: " << duration.count() << " микросекунд\n";
if (n <= 10) {
cout << "\nМатрица расстояний (первые " << min(10LL, n) << "x" << min(10LL, n) << "):\n";
for (int i = 0; i < min(10LL, n); i++) {
for (int j = 0; j < min(10LL, n); j++) {
if (D[i][j] == INF)
cout << " ∞ ";
else
cout << setw(3) << D[i][j] << " ";
}
cout << "\n";
}
}
}
// ============================================================
// 14. KRUSKAL SHORTEST PATH (Алгоритм Крускала + поиск пути в остовном дереве)
// ============================================================
// DFS для поиска пути в дереве
bool dfsPath(long long cur, long long target, const vector<vector<pair<long long, long long>>>& adj,
vector<bool>& visited, vector<long long>& path) {
if (cur == target) {
path.push_back(cur);
return true;
}
visited[cur] = true;
path.push_back(cur);
for (const auto& neighbor : adj[cur]) {
long long nxt = neighbor.first;
if (!visited[nxt]) {
if (dfsPath(nxt, target, adj, visited, path))
return true;
}
}
path.pop_back();
return false;
}
// Вывод описания вершин для Коньково
void printKonkovoVertices() {
cout << "\n=== ВЕРШИНЫ ГРАФА: КОНЬКОВО ===\n";
cout << "1 - Обручева × Профсоюзная (запад)\n";
cout << "2 - Обручева × Миклухо-Маклая\n";
cout << "3 - Миклухо-Маклая × Островитянова (юг)\n";
cout << "4 - Островитянова × Введенского (юг)\n";
cout << "5 - Введенского × Академика Волгина\n";
cout << "6 - Академика Волгина × Островитянова (восток)\n";
cout << "7 - Миклухо-Маклая × Бутлерова (юг)\n";
cout << "8 - Миклухо-Маклая × Профсоюзная (центр)\n";
cout << "9 - Профсоюзная × Обручева (запад)\n";
cout << "10 - Профсоюзная × Обручева (север)\n";
cout << "11 - Бутлерова × Островитянова (центр)\n";
cout << "12 - Островитянова × Бутлерова (восток)\n";
cout << "13 - Севастопольский × Академика Волгина (восток)\n";
cout << "14 - Островитянова × Профсоюзная (восток)\n";
cout << "15 - Профсоюзная × Миклухо-Маклая (север)\n";
cout << "16 - Обручева × Профсоюзная (северо-восток)\n";
cout << "17 - Профсоюзная × Обручева (восток)\n";
cout << "18 - Профсоюзная × Севастопольский (северо-восток)\n";
cout << "19 - Севастопольский проспект (восточная граница)\n";
}
// Вывод описания вершин для Арбата
void printArbatVertices() {
cout << "\n=== ВЕРШИНЫ ГРАФА: АРБАТ ===\n";
cout << "1 - Смоленская ул. × набережная (юго-запад)\n";
cout << "2 - Смоленская ул. × Новинский бульвар (юг-центр)\n";
cout << "3 - Новый Арбат × Смоленская ул. (запад-центр)\n";
cout << "4 - Новый Арбат × ул. Арбат (Арбатские Ворота, центр)\n";
cout << "5 - ул. Арбат × Арбатская пл. (центр-восток)\n";
cout << "6 - Арбатская пл. × Воздвиженка (восток)\n";
cout << "7 - Новый Арбат × Поварская ул. (север)\n";
}
// Получение графа Коньково
vector<Edge> getKonkovoGraph() {
return {
Edge(1, 2, 200), Edge(1, 9, 700),
Edge(2, 8, 700), Edge(2, 3, 800),
Edge(3, 7, 350), Edge(3, 4, 200),
Edge(4, 6, 500), Edge(4, 5, 600),
Edge(9, 8, 200), Edge(8, 7, 450), Edge(8, 10, 600),
Edge(7, 11, 200), Edge(7, 6, 350),
Edge(6, 5, 200), Edge(6, 12, 200),
Edge(5, 13, 400),
Edge(11, 12, 350), Edge(11, 15, 200),
Edge(12, 14, 200),
Edge(13, 14, 250), Edge(13, 19, 600),
Edge(14, 15, 350), Edge(14, 18, 300),
Edge(15, 10, 750), Edge(15, 17, 300),
Edge(10, 16, 100),
Edge(16, 17, 300),
Edge(17, 18, 300),
Edge(18, 19, 300)
};
}
// Получение графа Арбата
vector<Edge> getArbatGraph() {
return {
Edge(1, 2, 360), Edge(1, 3, 420), Edge(1, 4, 520), Edge(6, 7, 750),
Edge(2, 3, 500), Edge(2, 4, 380), Edge(2, 5, 790), Edge(2, 6, 810),
Edge(3, 4, 450), Edge(3, 7, 550),
Edge(4, 5, 650), Edge(4, 7, 500),
Edge(5, 6, 60), Edge(5, 7, 700)
};
}
// Вывод матрицы смежности с выровненными столбцами
void printAdjacencyTable(long long n, const vector<Edge>& edges) {
cout << "\n=== МАТРИЦА СМЕЖНОСТИ (ИСХОДНЫЙ ГРАФ) ===\n";
vector<vector<long long>> matrix(n + 1, vector<long long>(n + 1, 0));
for (const auto& e : edges) {
matrix[e.u][e.v] = e.weight;
matrix[e.v][e.u] = e.weight;
}
const int CELL_WIDTH = 5;
cout << " |";
for (long long j = 1; j <= n; j++) {
cout << setw(CELL_WIDTH) << j;
}
cout << "\n";
cout << "---+";
for (long long j = 1; j <= n; j++) {
cout << string(CELL_WIDTH, '-');
}
cout << "\n";
for (long long i = 1; i <= n; i++) {
cout << setw(2) << i << " |";
for (long long j = 1; j <= n; j++) {
if (matrix[i][j] == 0)
cout << setw(CELL_WIDTH) << "0";
else
cout << setw(CELL_WIDTH) << matrix[i][j];
}
cout << "\n";
}
}
void kruskalShortestPath() {
cout << "\n=== АЛГОРИТМ КРУСКАЛА + ПОИСК ПУТИ ===\n";
int graphChoice;
cout << "\nВыберите граф:\n";
cout << "1. Коньково\n";
cout << "2. Арбат\n";
cout << "Ваш выбор: ";
cin >> graphChoice;
long long n;
vector<Edge> edges;
if (graphChoice == 1) {
n = 19;
edges = getKonkovoGraph();
printKonkovoVertices();
}
else {
n = 7;
edges = getArbatGraph();
printArbatVertices();
}
printAdjacencyTable(n, edges);
// === КРУСКАЛ: построение минимального остовного дерева ===
vector<Edge> sortedEdges = edges;
sort(sortedEdges.begin(), sortedEdges.end());
DSU dsu(n);
vector<Edge> mstEdges;
long long mstWeight = 0;
for (const auto& e : sortedEdges) {
if (dsu.unite(e.u, e.v)) {
mstEdges.push_back(e);
mstWeight += e.weight;
if (mstEdges.size() == n - 1) break;
}
}
cout << "\n=== МИНИМАЛЬНОЕ ОСТОВНОЕ ДЕРЕВО (MST) ===\n";
cout << "Рёбра остовного дерева:\n";
for (const auto& e : mstEdges) {
cout << e.u << " --" << e.weight << "-- " << e.v << "\n";
}
// Построение списка смежности для MST
vector<vector<pair<long long, long long>>> mstAdj(n + 1);
for (const auto& e : mstEdges) {
mstAdj[e.u].push_back({e.v, e.weight});
mstAdj[e.v].push_back({e.u, e.weight});
}
// Выбор вершин для поиска пути
long long start, end;
cout << "\n=== ПОИСК ПУТИ В ОСТОВНОМ ДЕРЕВЕ ===\n";
cout << "Введите начальную вершину (1.." << n << "): ";
cin >> start;
cout << "Введите конечную вершину (1.." << n << "): ";
cin >> end;
if (start < 1 || start > n || end < 1 || end > n) {
cout << "Ошибка: неверный номер вершины!\n";
return;
}
// DFS для поиска пути
vector<bool> visited(n + 1, false);
vector<long long> path;
if (dfsPath(start, end, mstAdj, visited, path)) {
cout << "\nПуть найден в остовном дереве:\n";
cout << "Маршрут: ";
for (size_t i = 0; i < path.size(); i++) {
cout << path[i];
if (i < path.size() - 1) cout << " -> ";
}
cout << "\n";
long long pathWeight = 0;
for (size_t i = 0; i < path.size() - 1; i++) {
for (const auto& neighbor : mstAdj[path[i]]) {
long long v = neighbor.first;
long long w = neighbor.second;
if (v == path[i + 1]) {
pathWeight += w;
break;
}
}
}
cout << "Длина пути в остовном дереве: " << pathWeight << " м\n";
cout << "\nПРЕДУПРЕЖДЕНИЕ:\n";
cout << "Этот путь минимален в рамках остовного дерева,\n";
cout << "но не обязательно является кратчайшим в исходном графе.\n";
}
else {
cout << "X Путь не найден (граф несвязный)\n";
}
}