Bobert0032

Пособие/«Система непересекающихся множеств»

Aug 15th, 2023 (edited)
100
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
C++ 4.67 KB | None | 0 0
  1. #include <iostream>
  2. #include <vector>
  3. #include <string>
  4.  
  5. using namespace std;
  6.  
  7. vector<int> p, sz; // создаём вектора p(массив ссылок), sz(массив размеров множеств)
  8.  
  9. int get_p(int v) { // get_p(v) возвращает номер множества, которому принадлежит v-ый элемент
  10.     if (p[v] == v) { // Если элемент ссылается на самого себя, то это корень, следовательно это искомый ответ
  11.         return v; // возвращаем искомый ответ
  12.     }
  13.     // одновременно находим корень множества (оно в виде дерева), к которому принадлежит предок v и напрямую подвешиваем к этому корню v
  14.     return p[v] = get_p(p[v]);
  15. }
  16.  
  17. void unite(int a, int b) { // функция, объединяющая 2 множества
  18.     a = get_p(a); // находим корень множества, к которому принадлежит a
  19.     b = get_p(b); // находим корень множества, к которому принадлежит b
  20.     // Если размер множества, в котором корень a, больше размера множества, в котором корень b, то
  21.     // меняем значения в a и b
  22.     if (sz[a] > sz[b]) {
  23.         swap(a, b);
  24.     }
  25.     sz[b] += sz[a]; // увеличиваем размер множества с корнем b на размер множества с корнем a
  26.     p[a] = b; // подвешиваем a к b
  27. }
  28.  
  29. void solve() {
  30.     string query; // query - это очередной запрос
  31.     while (cin >> query) { // Если какой-то запрос считывается, то продолжаем работу программы
  32.         if (query == "RESET") { // если запрос - это "RESET", то сбрасываем все массивы
  33.             int n;
  34.             cin >> n; // считываем кол-во элементов
  35.             p.assign(n, 0); // меняем размер массива p; неважно, чем мы его заполним, так как эти значения мы всё равно присвоим циклом
  36.             sz.assign(n, 1); // меняем размер массива sz, заполняем его 1-ами, так как изначально i-ое множество состоит из одного элемента (i-го элемента)
  37.             for (int i = 0; i < n; ++i) p[i] = i; // так как изначально i-ое множество состоит только из i-го элемента, то i-ый элемент является корнем, а значит ссылается на самого себя
  38.             cout << "RESET DONE\n"; // Вывод этой фразы просто прописан в условии задачи
  39.         }
  40.         if (query == "JOIN") { // если запрос - это "JOIN", то нужно объединить множество, в котором содержится j-ый элемент и множество, в котором содержится k-ый элемент
  41.             int j, k;
  42.             cin >> j >> k; // считываем j и k
  43.             if (get_p(j) == get_p(k)) { // Если номера множеств, к которым принадлежат j и k совпадают, то они уже лежат в одном множестве
  44.                 cout << "ALREADY " << j << ' ' << k << '\n'; // Вывод этой строки прописан в условии задачи
  45.             } else {
  46.                 unite(j, k); // В противном случае объединяем множество, содержащее i-ый элемент, и множество, содержащее j-ый.
  47.             }
  48.         }
  49.         if (query == "CHECK") { // если запрос - это "CHECK", то нужно проверить 2 элемента, на принадлежность одному множеству
  50.             int j, k;
  51.             cin >> j >> k; // считываем j и k
  52.             if (get_p(j) == get_p(k)) { // Если номера множеств, к которым принадлежат j и k совпадают, то они уже лежат в одном множестве
  53.                 cout << "YES\n"; // Выводим "YES"
  54.             } else {
  55.                 cout << "NO\n"; // В противном случае выводим "NO"
  56.             }
  57.         }
  58.     }
  59. }
  60.  
  61. int main() {
  62.     solve();
  63.     return 0;
  64. }
Advertisement
Add Comment
Please, Sign In to add comment