Advertisement
Bobert0032

Пособие/«Цикл отрицательного веса»

Sep 19th, 2023 (edited)
1,423
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
C++ 5.85 KB | None | 0 0
  1. #include <algorithm>
  2. #include <iostream>
  3. #include <vector>
  4.  
  5. using namespace std;
  6.  
  7. struct Edge { // Создаём структуру ребра, которая содержит его начало, конец и вес
  8.     int a, b, w;
  9. };
  10.  
  11. const int INF = 1e9; // INF - это очень большое значение, которое превосходит модуль любого кратчайшего расстояния
  12.  
  13. void solve() {
  14.     int n;
  15.     cin >> n; // Считываем кол-во вершин в графе
  16.     vector<Edge> ve; // Создаём массив рёбер
  17.     for (int i = 0; i < n; ++i) { // Итерируемся по строкам матрицы смежности
  18.         for (int j = 0; j < n; ++j) { // Итерируемся по столбцам
  19.             int w;
  20.             cin >> w; // считываем вес ребра i->j
  21.             if (w == 100000) continue; // Если ребра нет (По условию в таком случае вес равен 100000), то пропускаем добавление этого ребра в массив
  22.             ve.push_back({i, j, w}); // Добавляем ребро в массив рёбер
  23.         }
  24.     }
  25.     vector<int> d(n, INF), p(n); // d[i] = x, означает, что  вес кратчайшего пути от 0-ой вершины до i-ой равен x
  26.                                  // p[i] = j обозначает, что в легчайшем пути, ведущем в i-ую вершину, есть ребро j -> i.
  27.     d[0] = 0; // расстояние от 0-ой вершины до самой себя равно 0
  28.     int start; // start - вершина, вес кратчайшее расстояние до которой изменится на n-ой (по счёту) фазе, если есть цикл отрицательного веса
  29.     for (int phase = 0; phase < n; ++phase) { // Перебираем фазу
  30.         start = -1; // устанавливаем в start какое-либо значение, которое не может быть номером вершины (В данном случае -1)
  31.         for (Edge edge : ve) { // Перебираем ребро, вдоль которого мы попытаемся сделать релаксацию
  32.             if (d[edge.b] > d[edge.a] + edge.w) { // Если кратчайшее расстояние до edge.b-ой вершины больше, чем кратчайшее расстояние до edge.a-ой вершины плюс вес ребра a->b, то можно успешно выполнить релаксацию
  33.                 d[edge.b] = max(-INF, d[edge.a] + edge.w); // Присваиваем новое известное кратчайшее расстояние до edge.b-ой вершины.
  34.                                                            // Нужно ограничить присваиваемое значений по нижней границе числом -INF, так как, если есть отрицательный цикл, то кратчайшее расстояние может чрезвычайно быстро стремиться к минус бесконечности, что может привести к числам, которые невозможно записать с помощью int/long long/...
  35.                 p[edge.b] = edge.a; // Указываем предка для edge.a-ой вершины
  36.                 start = edge.b; // Присваиваем номер вершины, для которой изменилось кратчайшее расстояние, start-у
  37.             }
  38.         }
  39.     }
  40.     if (start != -1) { // Если на n-ой (по счёту) фазе были изменения среди кратчайших расстояний, то цикл отрицательного веса существует
  41.         vector<int> path; // path - это вершины отрицательного цикла в порядке обхода
  42.         for (int i = 0; i < n; ++i) { // n раз "шагаем" назад, чтобы попасть в какую вершину отрицательного цикла
  43.             start = p[start];
  44.         }
  45.         int at = start; // at - текущая вершины отрицательного цикла
  46.         while (p[at] != start) { // Пока следующая вершина в порядке обхода не является изначальной --- продолжаем
  47.             path.push_back(at); // Добавляем в вершины цикла текущую вершину
  48.             at = p[at]; // Переход к следующей вершине (В обратном порядке, ведь мы "шагаем" назад) отрицательного цикла
  49.         }
  50.         path.push_back(at); // Добавляем последнюю вершину
  51.         reverse(path.begin(), path.end()); // Инвертируем вершины отрицательного цикла, так как мы записывали их в обратном порядке, а нам нужно вывести вершины в порядке обхода
  52.         cout << "YES\n"; // Выводим "YES", так как отрицательный цикл в графе есть
  53.         cout << path.size() << '\n'; // Выводим кол-во вершин в этом цикле
  54.         for (auto el : path) { // Выводим вершины отрицательного цикла
  55.             cout << el + 1 << ' ';
  56.         }
  57.     } else { // Если на n-ой (по счёту) фазе не было изменений среди кратчайших расстояний, то отрицательного цикла нет
  58.         cout << "NO";
  59.     }
  60. }
  61.  
  62. int main() {
  63.     solve();
  64.     return 0;
  65. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement