// Task: 28-5-3 Trezor s alarmem // Author: Pali Rohár // Input format: // N M // // N - number of vertices // M - number of edges // from, to - directed edge // vertex 0 - start // vertex N-1 - end // Output format: // one vertex per line // Example input: // 8 10 // 2 4 // 1 2 // 3 4 // 1 3 // 5 6 // 3 5 // 6 8 // 4 5 // 7 8 // 6 7 // Example output: // 5 // 6 #include #include #include typedef std::vector vertices; typedef std::vector graph; typedef std::queue vertices_queue; void dfs_filter(int v, const graph &graph, vertices &accessible) { accessible[v] = true; for ( size_t i = 0; i < graph[v].size(); ++i ) if ( ! accessible[graph[v][i]] ) dfs_filter(graph[v][i], graph, accessible); } vertices filter_accessible(const graph &digraph, const graph &digraph_reverse) { size_t N = digraph.size(); vertices accessible_from_start(N); vertices accessible_from_end(N); dfs_filter(0, digraph, accessible_from_start); dfs_filter(N-1, digraph_reverse, accessible_from_end); vertices accessible(N); for ( size_t i = 0; i < N; ++i ) accessible[i] = accessible_from_start[i] && accessible_from_end[i]; return accessible; } vertices toposort(const graph &digraph_reverse, const vertices &accessible) { size_t N = digraph_reverse.size(); vertices degree(N); vertices_queue queue; size_t accessible_count = 0; for ( size_t i = 0; i < N; ++i ) { if ( ! accessible[i] ) continue; ++accessible_count; for ( size_t j = 0; j < digraph_reverse[i].size(); ++j ) ++degree[digraph_reverse[i][j]]; } for ( size_t i = 0; i < N; ++i ) if ( accessible[i] && degree[i] == 0 ) queue.push(i); size_t top = accessible_count; vertices order_map(N, (size_t)-1); while ( ! queue.empty() ) { --top; size_t v = queue.front(); queue.pop(); order_map[v] = top; for ( size_t i = 0; i < digraph_reverse[v].size(); ++i ) { size_t neighbor = digraph_reverse[v][i]; if ( ! accessible[neighbor] ) continue; --degree[neighbor]; if ( degree[neighbor] == 0 ) queue.push(neighbor); } } if ( top != 0 ) { std::cerr << "Input graph is not acyclic" << std::endl; return vertices(N, (size_t)-1); } return order_map; } void print_criticals(const graph &digraph, const vertices &order_map) { size_t N = digraph.size(); size_t maximal = 0; vertices ordered(N); size_t accessible_count = 0; for ( size_t i = 0; i < N; ++i ) { if ( order_map[i] == (size_t)-1 ) continue; ordered[order_map[i]] = i; ++accessible_count; } for ( size_t i = 0; i < accessible_count; ++i ) { if ( maximal == i && maximal != 0 && maximal != accessible_count-1 ) std::cout << i+1 << std::endl; const vertices &neighbors = digraph[ordered[i]]; for ( size_t j = 0; j < neighbors.size(); ++j ) if ( maximal < order_map[neighbors[j]] ) maximal = order_map[neighbors[j]]; } } int main() { size_t N, M; std::cin >> N >> M; graph digraph(N); graph digraph_reverse(N); for ( size_t i = 0; i < M; ++i ) { size_t from, to; std::cin >> from >> to; --from; --to; digraph[from].push_back(to); digraph_reverse[to].push_back(from); } const vertices accessible = filter_accessible(digraph, digraph_reverse); const vertices order_map = toposort(digraph_reverse, accessible); print_criticals(digraph, order_map); }