Advertisement
Tvor0zhok

Графы обходы графа

Oct 16th, 2022 (edited)
1,392
1
Never
1
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
C++ 20.06 KB | None | 1 0
  1. ////////////////////////////////////////////////////////////////////////////////////////////////////////
  2. // GOOGLE DRIVE: https://drive.google.com/drive/folders/1eNXlQ50LanvYKPj_qr-Qr2qJmPa2o_Ze?usp=sharing //
  3. ////////////////////////////////////////////////////////////////////////////////////////////////////////
  4.  
  5. ///////////////////////////////////
  6. //            Graph.h            //
  7. ///////////////////////////////////
  8.  
  9. #pragma once
  10. #include <iostream>
  11. #include <iomanip>
  12. #include <fstream>
  13. #include <vector>
  14. #include <queue>
  15. #include <map>
  16. using namespace std;
  17.  
  18. /// <summary>
  19. /// Граф
  20. /// </summary>
  21. /// <typeparam name="Vertice"> тип вершин графа </typeparam>
  22. /// <typeparam name="Edge"> тип ребер графа (int по умолчанию) </typeparam>
  23. template <class Vertice, class Edge = int>
  24. class Graph
  25. {
  26.     /// <summary>
  27.     /// Количество вершин и ребер в графе
  28.     /// </summary>
  29.     int _N = 0, _M = 0;
  30.  
  31.     /// <summary>
  32.     /// Критерий ориентированности и взвешенности графа
  33.     /// </summary>
  34.     bool IsDirected = false, IsWeighted = false;
  35.  
  36.     /// <summary>
  37.     /// Список смежности графа
  38.     /// </summary>
  39.     map <Vertice, map<Vertice, Edge>> graph;
  40.  
  41. public:
  42.  
  43.     /// <summary>
  44.     /// Конструктор по умолчанию
  45.     /// </summary>
  46.     Graph() {};
  47.  
  48.     /// <summary>
  49.     /// Конструктор, создающий пустой граф, определяющий
  50.     /// ориентированность и взвешенность графа
  51.     /// </summary>
  52.     /// <param name="direction"> критерий ориентированности </param>
  53.     /// <param name="weighting"> критерий взвешенности </param>
  54.     Graph(string direction, string weighting)
  55.     {
  56.         if (direction == "directed") IsDirected = true;
  57.         if (weighting == "weighted") IsWeighted = true;
  58.     }
  59.  
  60.     /// <summary>
  61.     /// Конструктор, считывающий информацию из файла
  62.     /// или из консоли (stdin)
  63.     /// </summary>
  64.     /// <param name="filePath"> путь к файлу или ключевое слово stdin </param>
  65.     Graph(string filePath)
  66.     {
  67.         ifstream fin;
  68.  
  69.         if (filePath == "stdin") fin = ifstream(stdin);
  70.         else fin = ifstream(filePath);
  71.  
  72.         string cmd, direction, weighting;
  73.         fin >> cmd >> direction >> weighting;
  74.  
  75.         *this = Graph(direction, weighting);
  76.  
  77.         fin >> cmd >> _N;
  78.  
  79.         for (int i = 0; i < _N; ++i)
  80.         {
  81.             Vertice v; fin >> v;
  82.             graph.insert(pair<Vertice, map<Vertice, Edge>>(v, map<Vertice, Edge>()));
  83.         }
  84.  
  85.         fin >> cmd >> _M;
  86.  
  87.         for (int i = 0; i < _M; ++i)
  88.         {
  89.             Vertice u, v; Edge w; fin >> u >> v;
  90.  
  91.             if (!IsWeighted) w = 1;
  92.             else fin >> w;
  93.  
  94.             graph[u].insert(pair<Vertice, Edge>(v, w));
  95.             if (!IsDirected) graph[v].insert(pair<Vertice, Edge>(u, w));
  96.         }
  97.  
  98.         if (filePath != "stdin") fin.close();
  99.     }
  100.  
  101.     /// <summary>
  102.     /// Количество вершин графа
  103.     /// </summary>
  104.     /// <returns> количество вершин графа </returns>
  105.     int n() { return _N; }
  106.  
  107.     /// <summary>
  108.     /// Количество ребер графа
  109.     /// </summary>
  110.     /// <returns> количество ребер графа </returns>
  111.     int m() { return _M; }
  112.  
  113.     /// <summary>
  114.     /// Метод, выдающий информацию об
  115.     /// ориентированности графа
  116.     /// </summary>
  117.     /// <returns> true, если граф ориентированный, иначе - false </returns>
  118.     bool isDirected() { return IsDirected; }
  119.  
  120.     /// <summary>
  121.     /// Метод, выдающий информацию о
  122.     /// взвешенности графа
  123.     /// </summary>
  124.     /// <returns> true, если граф взвешенный, иначе - false </returns>
  125.     bool isWeighted() { return IsWeighted; }
  126.  
  127.     /// <summary>
  128.     /// Метод, возращающий список смежности графа
  129.     /// </summary>
  130.     /// <returns> список смежности графа </returns>
  131.     map<Vertice, map<Vertice, Edge>> edges() { return graph; }
  132.  
  133.     /// <summary>
  134.     /// Добавление вершины в граф
  135.     /// </summary>
  136.     /// <param name="v"> добавляемая в граф вершина </param>
  137.     void addVertice(Vertice v)
  138.     {
  139.         try
  140.         {
  141.             if (graph.find(v) != graph.end()) throw "Добавление вершины: заданная вершина уже есть в графе";
  142.             else
  143.             {
  144.                 ++_N;
  145.                 graph.insert(pair<Vertice, map<Vertice, Edge>>(v, map<Vertice, Edge>()));
  146.             }
  147.         }
  148.         catch (const char* msg)
  149.         {
  150.             cout << msg << "\n";
  151.         }
  152.     }
  153.  
  154.     /// <summary>
  155.     /// Удаление вершины из графа
  156.     /// </summary>
  157.     /// <param name="v"> удаляемая из графа вершина </param>
  158.     void removeVertice(Vertice v)
  159.     {
  160.         try
  161.         {
  162.             if (graph.find(v) == graph.end()) throw "Удаление вершины: в графе отсутствует заданная вершина";
  163.             else
  164.             {
  165.                 --_N; _M -= graph[v].size();
  166.  
  167.                 graph.erase(v);
  168.  
  169.                 for (auto p : graph)
  170.                     if (graph[p.first].find(v) != graph[p.first].end())
  171.                     {
  172.                         if (IsDirected) --_M;
  173.                         graph[p.first].erase(v);
  174.                     }
  175.             }
  176.         }
  177.         catch (const char* msg)
  178.         {
  179.             cout << msg << "\n";
  180.         }
  181.     }
  182.  
  183.     /// <summary>
  184.     /// Добавление ребра в граф
  185.     /// </summary>
  186.     /// <param name="u"> первая вершина ребра </param>
  187.     /// <param name="v"> вторая вершина ребра </param>
  188.     /// <param name="w"> вес ребра (для невзвешенных графов w = 1) </param>
  189.     void addEdge(Vertice u, Vertice v, Edge w)
  190.     {
  191.         try
  192.         {
  193.             if (graph.find(u) == graph.end() || graph.find(v) == graph.end()) throw "Добавление ребра: в графе отсутствует(ют) заданная(ые) вершина(ы)";
  194.             else if (!IsDirected && u == v) throw "Добавление ребра: невозможно добавить петлю в неориентированный граф";
  195.             else if (graph[u].find(v) != graph[u].end()) throw "Добавление ребра: заданное ребро уже есть в графе";
  196.             else
  197.             {
  198.                 ++_M;
  199.                 graph[u][v] = w;
  200.                 if (!IsDirected) graph[v][u] = w;
  201.             }
  202.         }
  203.         catch (const char* msg)
  204.         {
  205.             cout << msg << "\n";
  206.         }
  207.     }
  208.  
  209.     /// <summary>
  210.     /// Удаление ребра из графа
  211.     /// </summary>
  212.     /// <param name="u"> первая вершина ребра </param>
  213.     /// <param name="v"> вторая вершина ребра </param>
  214.     void removeEdge(Vertice u, Vertice v)
  215.     {
  216.         try
  217.         {
  218.             if (graph.find(u) == graph.end() || graph.find(v) == graph.end()) throw "Удаление ребра: в графе отсутствует(ют) заданная(ые) вершина(ы)";
  219.             else
  220.             {
  221.                 if (graph[u].find(v) == graph[u].end()) throw "Удаление ребра: в графе отсутствует заданное ребро";
  222.                 else
  223.                 {
  224.                     --_M;
  225.                     graph[u].erase(v);
  226.                     if (!IsDirected) graph[v].erase(u);
  227.                 }
  228.             }
  229.         }
  230.         catch (const char* msg)
  231.         {
  232.             cout << msg << "\n";
  233.         }
  234.     }
  235.  
  236.     /// <summary>
  237.     /// Очищение графа (ориентированность
  238.     /// и взвешенность остаются прежними)
  239.     /// </summary>
  240.     void clear()
  241.     {
  242.         _N = 0; _M = 0;
  243.         graph.clear();
  244.     }
  245.  
  246.     /// <summary>
  247.     /// Вывод информации о графе в файл или
  248.     /// на консоль (stdout)
  249.     /// </summary>
  250.     /// <param name="filePath"> путь к файлу или ключевое слово stdout </param>
  251.     void print(string filePath)
  252.     {
  253.         ofstream fout;
  254.  
  255.         if (filePath == "stdout") fout = ofstream(stdout);
  256.         else fout = ofstream(filePath);
  257.  
  258.         if (filePath != "stdout")
  259.         {
  260.             fout << "GRAPH ";
  261.  
  262.             if (IsDirected) fout << "directed ";
  263.             else fout << "undirected ";
  264.  
  265.             if (IsWeighted) fout << "weighted\n";
  266.             else fout << "unweighted\n";
  267.  
  268.             fout << "VERTICES: " << _N << "\n";
  269.  
  270.             for (auto p : graph)
  271.                 fout << p.first << "\n";
  272.  
  273.             fout << "EDGES: " << _M << "\n";
  274.  
  275.             for (auto p1 : graph)
  276.             {
  277.                 Vertice u = p1.first;
  278.  
  279.                 for (auto p2 : p1.second)
  280.                 {
  281.                     Vertice v = p2.first; Edge w = p2.second;
  282.  
  283.                     if (IsDirected || u < v)
  284.                     {
  285.                         fout << u << " " << v << " ";
  286.                         if (IsWeighted) fout << w;
  287.                         fout << "\n";
  288.                     }
  289.                 }
  290.             }
  291.  
  292.             fout.close();
  293.         }
  294.         else
  295.         {
  296.             fout << "GRAPH ";
  297.  
  298.             if (IsDirected) fout << "directed ";
  299.             else fout << "undirected ";
  300.  
  301.             if (IsWeighted) fout << "weighted\n";
  302.             else fout << "unweighted\n";
  303.  
  304.             fout << "VERTICES: " << _N << "\n";
  305.  
  306.             for (auto p : graph)
  307.                 fout << p.first << "\n";
  308.  
  309.             fout << "EDGES: " << _M << "\n";
  310.  
  311.             for (auto p1 : graph)
  312.             {
  313.                 Vertice u = p1.first;
  314.  
  315.                 fout << u << ": ";
  316.  
  317.                 for (auto p2 : p1.second)
  318.                 {
  319.                     Vertice v = p2.first; Edge w = p2.second;
  320.  
  321.                     if (!IsWeighted) fout << v << " ";
  322.                     else fout << "(" << v << ", " << w << ") ";
  323.                 }
  324.  
  325.                 fout << "\n";
  326.             }
  327.         }
  328.     }
  329. };
  330.  
  331. /// <summary>
  332. /// Поиск в глубину - порядок вершин по выходу из рекурсии
  333. /// </summary>
  334. /// <typeparam name="Vertice"> тип вершин графа </typeparam>
  335. /// <typeparam name="Edge"> тип ребер графа </typeparam>
  336. /// <param name="edges"> список смежности графа </param>
  337. /// <param name="used"> массив значений посещена ли вершина или нет </param>
  338. /// <param name="order"> порядок вершин </param>
  339. /// <param name="u"> текущая вершина </param>
  340. template <class Vertice, class Edge>
  341. void DFS(map<Vertice, map<Vertice, Edge>>& edges, map <Vertice, bool>& used, vector <Vertice>& order, Vertice u)
  342. {
  343.     used[u] = 1;
  344.  
  345.     for (auto p : edges[u])
  346.     {
  347.         Vertice v = p.first;
  348.         if (!used[v]) DFS(edges, used, order, v);
  349.     }
  350.  
  351.     order.push_back(u);
  352. }
  353.  
  354. /// <summary>
  355. /// Поиск сильных компонент связности орграфа
  356. /// (алгоритм Косарайю)
  357. /// </summary>
  358. /// <typeparam name="Vertice"> тип вершин графа </typeparam>
  359. /// <typeparam name="Edge"> тип ребер графа </typeparam>
  360. /// <param name="g"> граф </param>
  361. template <class Vertice, class Edge>
  362. void SCC(Graph<Vertice, Edge>& g)
  363. {
  364.     try
  365.     {
  366.         if (!g.isDirected()) throw "Задание II (обходы графа): граф должен быть ориентированным";
  367.         else
  368.         {
  369.             // ШАГ 1: сформировать порядок вершин
  370.  
  371.             map <Vertice, map <Vertice, Edge>> edges = g.edges();
  372.             map <Vertice, bool> used;
  373.             vector <Vertice> order;
  374.  
  375.             for (auto p : edges)
  376.             {
  377.                 Vertice u = p.first;
  378.                 if (!used[u]) DFS(edges, used, order, u);
  379.             }
  380.  
  381.             // ШАГ 2: перевернуть порядок, инвертировать ребра
  382.  
  383.             reverse(order.begin(), order.end());
  384.  
  385.             used.clear();
  386.  
  387.             int cnt = 0;
  388.  
  389.             map <Vertice, map <Vertice, Edge>> inv_edges;
  390.  
  391.             for (auto p1 : edges)
  392.             {
  393.                 Vertice u = p1.first;
  394.  
  395.                 for (auto p2 : edges[u])
  396.                 {
  397.                     Vertice v = p2.first; Edge w = p2.second;
  398.                     inv_edges[v][u] = w;
  399.                 }
  400.             }
  401.  
  402.             // ШАГ 3: поиск сильных компонент связности оргафа
  403.  
  404.             for (auto u : order)
  405.                 if (!used[u])
  406.                 {
  407.                     vector <Vertice> component;
  408.                     DFS(inv_edges, used, component, u);
  409.  
  410.                     cout << "Компонента №" << ++cnt << ": " << component.size() << "\n";
  411.                     for (auto v : component)
  412.                         cout << v << " ";
  413.  
  414.                     cout << "\n";
  415.                 }
  416.         }
  417.     }
  418.     catch (const char* msg)
  419.     {
  420.         cout << msg << "\n";
  421.     }
  422. }
  423.  
  424. /// <summary>
  425. /// Поиск кратчайшего пути от каждой вершины орграфа
  426. /// до заданной вершины u
  427. /// </summary>
  428. /// <typeparam name="Vertice"> тип вершин графа </typeparam>
  429. /// <typeparam name="Edge"> тип ребер графа </typeparam>
  430. /// <param name="g"> граф </param>
  431. /// <param name="u"> заданная вершина </param>
  432. template <class Vertice, class Edge>
  433. void PathsToVertice(Graph<Vertice, Edge>& g, Vertice u)
  434. {
  435.     try
  436.     {
  437.         if (!g.isDirected()) throw "Задание II (обходы графа): граф должен быть ориентированным";
  438.         else
  439.         {
  440.             map <Vertice, map<Vertice, Edge>> edges = g.edges(), inv_edges;
  441.  
  442.             int INF = (int)1e9 + 7;
  443.             map <Vertice, int> dist;
  444.             map <Vertice, Vertice> parent;
  445.  
  446.             for (auto p1 : edges)
  447.             {
  448.                 Vertice u = p1.first;
  449.  
  450.                 if (inv_edges.find(u) == inv_edges.end())
  451.                     inv_edges.insert(pair<Vertice, map<Vertice, Edge>>(u, map<Vertice, Edge>()));
  452.  
  453.                 dist[u] = INF;
  454.  
  455.                 for (auto p2 : edges[u])
  456.                 {
  457.                     Vertice v = p2.first; Edge w = p2.second;
  458.                     inv_edges[v][u] = w;
  459.                 }
  460.             }
  461.  
  462.             dist[u] = 0; parent[u] = u;
  463.             queue <Vertice> q; q.push(u);
  464.  
  465.             while (!q.empty())
  466.             {
  467.                 Vertice u = q.front(); q.pop();
  468.  
  469.                 for (auto p : inv_edges[u])
  470.                 {
  471.                     Vertice v = p.first;
  472.  
  473.                     if (dist[v] == INF)
  474.                     {
  475.                         dist[v] = dist[u] + 1;
  476.                         parent[v] = u;
  477.                         q.push(v);
  478.                     }
  479.                 }
  480.             }
  481.  
  482.             for (auto p : inv_edges)
  483.             {
  484.                 Vertice v = p.first;
  485.                 if (u == v) continue;
  486.  
  487.                 cout << "Путь " << v << " -> " << u;
  488.  
  489.                 if (parent.find(v) == parent.end()) cout << ": пути нет :(";
  490.                 else
  491.                 {
  492.                     int dist = 0;
  493.  
  494.                     vector <Vertice> path;
  495.  
  496.                     while (v != u)
  497.                     {
  498.                         path.push_back(v);
  499.                         v = parent[v];
  500.                     }
  501.  
  502.                     cout << " (" << path.size() << ") : ";
  503.  
  504.                     for (auto v : path)
  505.                         cout << v << " ";
  506.  
  507.                     cout << u;
  508.                 }
  509.  
  510.                 cout << "\n";
  511.             }
  512.         }
  513.     }
  514.     catch (const char* msg)
  515.     {
  516.         cout << msg << "\n";
  517.     }
  518. }
  519.  
  520. //////////////////////////////////////////////
  521. //            ConsoleInterface.h            //
  522. //////////////////////////////////////////////
  523.  
  524. #pragma once
  525. #include "Graph.h"
  526. #include <vector>
  527. #include <string>
  528.  
  529. /// <summary>
  530. /// Консольный интерфейс, работающий с одним графом
  531. /// </summary>
  532. /// <typeparam name="Vertice"> тип вершин графа </typeparam>
  533. /// <typeparam name="Edge"> тип ребер графа </typeparam>
  534. template <class Vertice, class Edge = int>
  535. class ConsoleInterface
  536. {
  537.     /// <summary>
  538.     /// Граф
  539.     /// </summary>
  540.     Graph<Vertice, Edge> g;
  541.  
  542.     /// <summary>
  543.     /// Вывод на консоль списка доступных команд
  544.     /// </summary>
  545.     void Hint()
  546.     {
  547.         cout << "+---------------------------------------+\n";
  548.         cout << "|             СПИСОК КОМАНД             |\n";
  549.         cout << "+---------------------------------------+\n";
  550.         cout << "|  1. CREATE GRAPH direction weighting  |\n";
  551.         cout << "|  2. CREATE GRAPH filePath             |\n";
  552.         cout << "|  3. ADD VERTICE v                     |\n";
  553.         cout << "|  4. REMOVE VERTICE v                  |\n";
  554.         cout << "|  5. ADD EDGE u v [w]                  |\n";
  555.         cout << "|  6. REMOVE EDGE u w                   |\n";
  556.         cout << "|  7. CLEAR GRAPH                       |\n";
  557.         cout << "|  8. PRINT GRAPH filePath              |\n";
  558.         cout << "|  9. TASK 1                            |\n";
  559.         cout << "|  10. TASK 2 u                         |\n";
  560.         cout << "|  10. GET HINT                         |\n";
  561.         cout << "|  11. EXIT                             |\n";
  562.         cout << "+---------------------------------------+\n";
  563.     }
  564.  
  565. public:
  566.  
  567.     /// <summary>
  568.     /// Конструктор по умолчанию
  569.     /// </summary>
  570.     ConsoleInterface() {};
  571.  
  572.     /// <summary>
  573.     /// Запуск интерфейса
  574.     /// </summary>
  575.     void Start()
  576.     {
  577.         Hint();
  578.  
  579.         while (true)
  580.         {
  581.             cout << ">> ";
  582.  
  583.             string w1; cin >> w1;
  584.  
  585.             if (w1 == "CREATE")
  586.             {
  587.                 string w2, w3; cin >> w2 >> w3;
  588.  
  589.                 if (w3 == "directed" || w3 == "undirected")
  590.                 {
  591.                     string w4; cin >> w4;
  592.                     g = Graph<Vertice, Edge>(w3, w4);
  593.                 }
  594.                 else g = Graph<Vertice, Edge>(w3);
  595.             }
  596.             else if (w1 == "ADD")
  597.             {
  598.                 string w2; cin >> w2;
  599.  
  600.                 if (w2 == "VERTICE")
  601.                 {
  602.                     Vertice w3; cin >> w3;
  603.                     g.addVertice(w3);
  604.                 }
  605.                 else
  606.                 {
  607.                     Vertice w3, w4; Edge w5; cin >> w3 >> w4;
  608.  
  609.                     if (!g.isWeighted()) w5 = 1;
  610.                     else cin >> w5;
  611.  
  612.                     g.addEdge(w3, w4, w5);
  613.                 }
  614.             }
  615.             else if (w1 == "REMOVE")
  616.             {
  617.                 string w2; cin >> w2;
  618.  
  619.                 if (w2 == "VERTICE")
  620.                 {
  621.                     Vertice w3; cin >> w3;
  622.                     g.removeVertice(w3);
  623.                 }
  624.                 else
  625.                 {
  626.                     Vertice w3, w4; cin >> w3 >> w4;
  627.                     g.removeEdge(w3, w4);
  628.                 }
  629.             }
  630.             else if (w1 == "CLEAR")
  631.             {
  632.                 string w2; cin >> w2;
  633.                 g.clear();
  634.             }
  635.             else if (w1 == "PRINT")
  636.             {
  637.                 string w2, w3; cin >> w2 >> w3;
  638.                 g.print(w3);
  639.             }
  640.             else if (w1 == "TASK")
  641.             {
  642.                 int w2; cin >> w2;
  643.  
  644.                 if (w2 == 1) SCC(g);
  645.                 else if (w2 == 2)
  646.                 {
  647.                     Vertice u; cin >> u;
  648.                     PathsToVertice(g, u);
  649.                 }
  650.             }
  651.             else if (w1 == "GET")
  652.             {
  653.                 string w2; cin >> w2;
  654.                 Hint();
  655.             }
  656.             else if (w1 == "EXIT")
  657.             {
  658.                 break;
  659.             }
  660.         }
  661.     }
  662. };
  663.  
  664. /////////////////////////////////////
  665. //            Graph.cpp            //
  666. /////////////////////////////////////
  667.  
  668. #include "ConsoleInterface.h"
  669. #include <Windows.h>
  670.  
  671. int main()
  672. {
  673.     SetConsoleCP(1251);
  674.     SetConsoleOutputCP(1251);
  675.  
  676.     ConsoleInterface<string, string> consoleInterface;
  677.     consoleInterface.Start();
  678.  
  679.     return 0;
  680. }
Advertisement
Comments
Add Comment
Please, Sign In to add comment
Advertisement