Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- #include <algorithm>
- #include <iostream>
- #include <map>
- #include <vector>
- #include <utility>
- //std::vector<std::vector<int>> graph;
- //std::vector<std::vector<int>> reversed_graph;
- //std::vector<std::pair<int, int>> t_out;
- //std::vector<std::pair<int, int>> edges;
- //std::vector<bool> color_good;
- //std::vector<int> color;
- //
- //int cur_time = 0;
- //int cur_color = 1;
- typedef std::vector<std::vector<int>> AdjacencyList;
- typedef std::vector<std::pair<int, int>> EdgeList;
- struct GameResult {
- int left_player, right_player;
- int result;
- };
- struct InputData {
- int employee_count;
- std::vector<GameResult> games;
- };
- class Graph {
- public:
- explicit Graph(int vertex_count) : adjacency_list_(vertex_count + 1) {
- }
- void AddEdge(int from, int to) {
- adjacency_list_[from].push_back(to);
- }
- const std::vector<int>& GetNeighbours(int vertex) const {
- return adjacency_list_[vertex];
- }
- int VertexCount() const {
- return static_cast<int>(adjacency_list_.size() - 1);
- }
- private:
- AdjacencyList adjacency_list_;
- };
- class VisitorBase {
- public:
- void DiscoverVertex(const Graph& graph, int vertex) const {
- }
- void FinishVertex(const Graph& graph, int vertex) const {
- }
- };
- class ForwardDFSVisitor : public VisitorBase {
- public:
- ForwardDFSVisitor(std::vector<int>* exit_time, int* exit_time_counter)
- : exit_time_(exit_time), exit_time_counter_(exit_time_counter) {
- }
- void FinishVertex(const Graph& graph, int vertex) const {
- exit_time_->operator[](vertex) = (*exit_time_counter_)++;
- }
- private:
- int* exit_time_counter_;
- std::vector<int>* exit_time_;
- };
- class BackwardDFSVisitor : public VisitorBase {
- public:
- BackwardDFSVisitor(std::vector<int>* strongly_connected_component_id, int* id_counter)
- : strongly_connected_component_id_(strongly_connected_component_id),
- id_counter_(id_counter) {
- }
- void DiscoverVertex(const Graph& graph, int vertex) const {
- strongly_connected_component_id_->operator[](vertex) = *id_counter_;
- }
- private:
- std::vector<int>* strongly_connected_component_id_;
- int* id_counter_;
- };
- InputData ReadGameResultsFromInput(std::istream& input) {
- int employee_count, games_count;
- input >> employee_count >> games_count;
- std::vector<GameResult> game_results;
- for (int i = 0; i < games_count; ++i) {
- int first_player, second_player, result;
- input >> first_player >> second_player >> result;
- game_results.push_back({first_player, second_player, result});
- }
- return {employee_count, game_results};
- }
- Graph CreateRelationshipsGraph(const InputData& input_data) {
- Graph graph(input_data.employee_count);
- for (const auto& game : input_data.games) {
- if (game.result == 1) {
- graph.AddEdge(game.left_player, game.right_player);
- } else if (game.result == 2) {
- graph.AddEdge(game.right_player, game.left_player);
- }
- }
- return graph;
- }
- Graph Transpose(const Graph& graph) {
- Graph reversed_graph(graph.VertexCount());
- for (int i = 1; i <= graph.VertexCount(); ++i) {
- const auto& adjacent_vertices = graph.GetNeighbours(i);
- for (size_t j = 0; j < adjacent_vertices.size(); ++j) {
- reversed_graph.AddEdge(adjacent_vertices[j], i);
- }
- }
- return reversed_graph;
- }
- template <typename Graph, typename Visitor>
- void DepthFirstSearch(const Graph& graph, Visitor visitor, int vertex, std::vector<int>& color) {
- color[vertex] = 1;
- visitor.DiscoverVertex(graph, vertex);
- for (size_t i = 0; i < graph.GetNeighbours(vertex).size(); ++i) {
- int to = graph.GetNeighbours(vertex)[i];
- if (!color[to]) {
- DepthFirstSearch(graph, visitor, to, color);
- }
- }
- visitor.FinishVertex(graph, vertex);
- }
- std::vector<int> TopologicalSort(const Graph& graph) {
- std::vector<int> color(graph.VertexCount() + 1, 0);
- std::vector<int> exit_times(graph.VertexCount() + 1, 0);
- int time_counter = 1;
- ForwardDFSVisitor forward_dfs_visitor(&exit_times, &time_counter);
- for (int i = 1; i <= graph.VertexCount(); ++i) {
- if (color[i] == 0) {
- DepthFirstSearch(graph, forward_dfs_visitor, i, color);
- }
- }
- std::vector<std::pair<int, int>> exit_time_and_index(graph.VertexCount());
- for (size_t i = 0; i < exit_times.size(); ++i) {
- exit_time_and_index.emplace_back(exit_times[i + 1], static_cast<int>(i));
- }
- std::sort(exit_time_and_index.begin(), exit_time_and_index.end(),
- [](auto lhs, auto rhs) {
- return lhs > rhs;
- });
- std::vector<int> topologically_sorted_vertices(graph.VertexCount() + 1);
- for (size_t i = 0; i < topologically_sorted_vertices.size(); ++i) {
- topologically_sorted_vertices[i] = exit_time_and_index[i].second;
- }
- return topologically_sorted_vertices;
- }
- std::pair<std::vector<int>, int> FindStronglyConnectedComponents(const Graph& graph) {
- auto transposed_graph = Transpose(graph);
- auto topologically_sorted_vertices = TopologicalSort(graph);
- std::vector<int> strongly_connected_component_id(graph.VertexCount() + 1, 0);
- std::vector<int> color(graph.VertexCount(), 0);
- int id_counter = 1;
- BackwardDFSVisitor backward_dfs_visitor(&strongly_connected_component_id, &id_counter);
- for (size_t i = 0; i < topologically_sorted_vertices.size(); ++i) {
- if (color[topologically_sorted_vertices[i]] == 0) {
- DepthFirstSearch(graph, backward_dfs_visitor, topologically_sorted_vertices[i], color);
- ++id_counter;
- }
- }
- return std::make_pair(strongly_connected_component_id, id_counter - 1);
- }
- std::vector<int> FindStronglyConnectedComponentsSizes(const std::vector<int>& scc_id, int total_count) {
- std::vector<int> result(total_count + 1, 0);
- for (size_t i = 1; i < scc_id.size(); ++i) {
- ++result[scc_id[i]];
- }
- return result;
- }
- std::vector<int> FindOuterStronglyConnectedComponents(const Graph& graph, const std::vector<int>& scc_id,
- int total_count) {
- std::vector<bool> outer_component(total_count + 1, true);
- for (int i = 1; i < graph.VertexCount(); ++i) {
- for (auto j : graph.GetNeighbours(i)) {
- if (scc_id[i] != scc_id[j]) {
- outer_component[scc_id[j]] = false;
- }
- }
- }
- std::vector<int> result;
- for (int i = 1; i <= total_count; ++i) {
- if (outer_component[i]) {
- result.push_back(i);
- }
- }
- return result;
- }
- int FindMinimalOuterSCCSize(const std::vector<int>& scc_sizes, std::vector<int> outer_scc_ids) {
- int result = -1;
- for (auto outer_scc_id : outer_scc_ids) {
- if (result == -1 || scc_sizes[outer_scc_id] < result) {
- result = scc_sizes[outer_scc_id];
- }
- }
- return result;
- }
- int main() {
- std::ios_base::sync_with_stdio(false);
- std::cin.tie(nullptr);
- InputData input_data = ReadGameResultsFromInput(std::cin);
- Graph graph = CreateRelationshipsGraph(input_data);
- auto strongly_connected_component_id_and_total_count =
- FindStronglyConnectedComponents(graph);
- auto scc_id = std::move(strongly_connected_component_id_and_total_count.first);
- auto total_count = strongly_connected_component_id_and_total_count.second;
- auto scc_sizes = FindStronglyConnectedComponentsSizes(scc_id, total_count);
- auto outer_scc_ids = FindOuterStronglyConnectedComponents(graph, scc_id, total_count);
- auto minimal_outer_scc_size = FindMinimalOuterSCCSize(scc_sizes, outer_scc_ids);
- std::cout << graph.VertexCount() - minimal_outer_scc_size + 1 << std::endl;
- return 0;
- }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement