/* * Copyright (C) 2015 Paweł Widera * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details: * http://www.gnu.org/licenses/gpl.html */ #include <iostream> #include <iterator> #include <vector> #include <deque> #include <unordered_set> #include <algorithm> using namespace std; vector<bool> marks; vector<int> stack; vector<int> cycle; unordered_set<int> critical_nodes; void update_critical_nodes(vector<int>& cycle) { // add all nodes of the first cycle as critical if (critical_nodes.empty()) { for (auto i: cycle) { critical_nodes.insert(i); } } // remove nodes not found in the current cycle as not critical else { unordered_set<int> common; for (auto i : cycle) { if (critical_nodes.count(i) > 0) { common.insert(i); } } critical_nodes = common; // if no critical nodes are left, stop the search if (critical_nodes.empty()) { cout << 0 << endl << endl; exit(0); } } //cout << "CRIT "; //copy(begin(critical_nodes), end(critical_nodes), ostream_iterator<int>(cout, " ")); //cout << endl; } // Tarjan algorithm for enumerating elementary cycles bool search(int node, int start, vector<vector<int>>& graph) { bool flag = false; cycle.push_back(node); marks[node] = true; stack.push_back(node); for (auto next_node: graph[node]) { if (next_node < start) { graph[next_node].clear(); } else if (next_node == start) { flag = true; update_critical_nodes(cycle); //cout << "CYCLE "; //copy(begin(cycle), end(cycle), ostream_iterator<int>(cout, " ")); //cout << endl; } else if (!marks[next_node]) { flag = search(next_node, start, graph) or flag; } } if (flag) { while (stack.back() != node) { int i = stack.back(); marks[i] = false; stack.pop_back(); } marks[node] = false; stack.pop_back(); } cycle.pop_back(); return flag; } int main() { ios::sync_with_stdio(false); cin.tie(nullptr); int n, m; cin >> n >> m; vector<vector<int>> graph(n); vector<unordered_set<int>> reversed_graph(n); // read graph int source, target; for (int i = 0; i < m; ++i) { cin >> source >> target; graph[source - 1].push_back(target - 1); reversed_graph[target - 1].insert(source - 1); } // find nodes without incoming edges deque<int> queue; for (int i = 0; i < n; ++i) { if (0 == reversed_graph[i].size()) { queue.push_back(i); } } // remove nodes without incoming edges, that can't be a part of a cycle while (!queue.empty()) { int node = queue.front(); queue.pop_front(); // remove incoming connections to out-nodes of the node for (auto out: graph[node]) { reversed_graph[out].erase(node); // if out-node has no incoming connections, add it to the queue if (0 == reversed_graph[out].size()) { queue.push_back(out); } } // remove node (clear its connections) graph[node].clear(); } // find not removed nodes vector<int> nodes; for (int i = 0; i < n; ++i) { if (graph[i].size() > 0) { nodes.push_back(i); } } // if all nodes were removed, the graph had no cycles if (0 == nodes.size()) { cout << "NIE" << endl; return 0; } // search for cycles marks.resize(n, false); for (auto node : nodes) { search(node, node, graph); // clear the marks while (!stack.empty()) { int i = stack.back(); marks[i] = false; stack.pop_back(); } } cout << critical_nodes.size() << endl; // sort and print critical nodes if any if (!critical_nodes.empty()) { vector<int> result; result.reserve(critical_nodes.size()); for (auto i : critical_nodes) { result.push_back(i); } sort(begin(result), end(result)); for (auto i : result) { cout << i + 1 << " "; } } cout << endl; return 0; }
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 | /* * Copyright (C) 2015 Paweł Widera * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details: * http://www.gnu.org/licenses/gpl.html */ #include <iostream> #include <iterator> #include <vector> #include <deque> #include <unordered_set> #include <algorithm> using namespace std; vector<bool> marks; vector<int> stack; vector<int> cycle; unordered_set<int> critical_nodes; void update_critical_nodes(vector<int>& cycle) { // add all nodes of the first cycle as critical if (critical_nodes.empty()) { for (auto i: cycle) { critical_nodes.insert(i); } } // remove nodes not found in the current cycle as not critical else { unordered_set<int> common; for (auto i : cycle) { if (critical_nodes.count(i) > 0) { common.insert(i); } } critical_nodes = common; // if no critical nodes are left, stop the search if (critical_nodes.empty()) { cout << 0 << endl << endl; exit(0); } } //cout << "CRIT "; //copy(begin(critical_nodes), end(critical_nodes), ostream_iterator<int>(cout, " ")); //cout << endl; } // Tarjan algorithm for enumerating elementary cycles bool search(int node, int start, vector<vector<int>>& graph) { bool flag = false; cycle.push_back(node); marks[node] = true; stack.push_back(node); for (auto next_node: graph[node]) { if (next_node < start) { graph[next_node].clear(); } else if (next_node == start) { flag = true; update_critical_nodes(cycle); //cout << "CYCLE "; //copy(begin(cycle), end(cycle), ostream_iterator<int>(cout, " ")); //cout << endl; } else if (!marks[next_node]) { flag = search(next_node, start, graph) or flag; } } if (flag) { while (stack.back() != node) { int i = stack.back(); marks[i] = false; stack.pop_back(); } marks[node] = false; stack.pop_back(); } cycle.pop_back(); return flag; } int main() { ios::sync_with_stdio(false); cin.tie(nullptr); int n, m; cin >> n >> m; vector<vector<int>> graph(n); vector<unordered_set<int>> reversed_graph(n); // read graph int source, target; for (int i = 0; i < m; ++i) { cin >> source >> target; graph[source - 1].push_back(target - 1); reversed_graph[target - 1].insert(source - 1); } // find nodes without incoming edges deque<int> queue; for (int i = 0; i < n; ++i) { if (0 == reversed_graph[i].size()) { queue.push_back(i); } } // remove nodes without incoming edges, that can't be a part of a cycle while (!queue.empty()) { int node = queue.front(); queue.pop_front(); // remove incoming connections to out-nodes of the node for (auto out: graph[node]) { reversed_graph[out].erase(node); // if out-node has no incoming connections, add it to the queue if (0 == reversed_graph[out].size()) { queue.push_back(out); } } // remove node (clear its connections) graph[node].clear(); } // find not removed nodes vector<int> nodes; for (int i = 0; i < n; ++i) { if (graph[i].size() > 0) { nodes.push_back(i); } } // if all nodes were removed, the graph had no cycles if (0 == nodes.size()) { cout << "NIE" << endl; return 0; } // search for cycles marks.resize(n, false); for (auto node : nodes) { search(node, node, graph); // clear the marks while (!stack.empty()) { int i = stack.back(); marks[i] = false; stack.pop_back(); } } cout << critical_nodes.size() << endl; // sort and print critical nodes if any if (!critical_nodes.empty()) { vector<int> result; result.reserve(critical_nodes.size()); for (auto i : critical_nodes) { result.push_back(i); } sort(begin(result), end(result)); for (auto i : result) { cout << i + 1 << " "; } } cout << endl; return 0; } |