Cod sursa(job #2909476)
Utilizator | Data | 13 iunie 2022 21:29:56 | |
---|---|---|---|
Problema | Mesaj4 | Scor | 100 |
Compilator | cpp-64 | Status | done |
Runda | Arhiva de probleme | Marime | 51.76 kb |
#include <iostream>
#include <fstream>
#include <vector>
#include <cstddef>
#include <cstdint>
#include <utility>
#include <memory>
#include <limits>
#include <stdexcept>
#include <algorithm>
#include <numeric>
struct edge_type {
uint32_t idm__u2;
uint32_t idm__u5;
};
edge_type build_edge (uint32_t arg__u2, uint32_t arg__u5) {
edge_type as__edge;
as__edge.idm__u2 = arg__u2;
as__edge.idm__u5 = arg__u5;
return as__edge;
}
struct mesaj4_type {
size_t idm__n = 0;
size_t idm__m = 0;
std::vector<edge_type> idm__edges;
std::vector<uint32_t> idm__neighbours_first;
std::vector<uint32_t> idm__neighbours_array;
std::vector<uint32_t> idm__queue;
std::vector<uint32_t> idm__parent;
size_t idm__cc;
};
template <typename T>
inline
T read_scalar_value_from_input_stream (std::istream & arg__is) {
T as__value;
arg__is >> as__value;
return as__value;
}
size_t double_that (size_t arg__m) {
size_t const as__maxval = std::numeric_limits<size_t>::max();
if ((as__maxval - arg__m) < arg__m) {
throw std::runtime_error("Implementation limits us."); }
return (arg__m + arg__m);
}
size_t one_plus (size_t arg__n) {
size_t const as__maxval = std::numeric_limits<size_t>::max();
if ((as__maxval - arg__n) < 1) {
throw std::runtime_error("Implementation limits us."); }
return (arg__n + 1);
}
void problem_mesaj4__read_the_input__all_of_it (mesaj4_type & arg__problem) {
std::ifstream as__is;
as__is.exceptions(std::ifstream::failbit | std::ifstream::badbit);
as__is.open("mesaj4.in");
uint64_t const as__n = read_scalar_value_from_input_stream<uint64_t>(as__is);
uint64_t const as__m = read_scalar_value_from_input_stream<uint64_t>(as__is);
if ((1 > as__n) || (100'000 < as__n)) {
throw std::invalid_argument("n."); }
if ((1 > as__m) || (100'000 < as__m)) {
throw std::invalid_argument("k."); }
std::vector<edge_type> as__edges(as__m);
size_t as__m2 = 0;
uint32_t as__u2 = 0;
uint32_t as__u5 = 0;
size_t as__j = 0;
for (as__j = 0; as__m > as__j; ++as__j) {
as__u2 = read_scalar_value_from_input_stream<uint32_t>(as__is);
as__u5 = read_scalar_value_from_input_stream<uint32_t>(as__is);
if ((1 > as__u2) || (1 > as__u5) || (as__n < as__u2) || (as__n < as__u5)) {
throw std::invalid_argument("one edge has been found to be out of whack."); }
if (as__u2 != as__u5) {
// Self loops would make no progress, in the message passing game.
// It does not matter if one is friend with oneself, in this game.
as__edges.at(as__m2) = build_edge(as__u2 - 1, as__u5 - 1);
as__m2 += 1; }}
if (as__m2 < as__m) {
as__edges.resize(as__m2); }
// Pass the baton!
arg__problem.idm__n = as__n;
arg__problem.idm__m = as__m2;
as__edges.swap(arg__problem.idm__edges);
}
void problem_mesaj4__allocate_all_the_space__id_est_memory__all_of_it (mesaj4_type & arg__problem) {
/* Having read the edges, let’s allocate all the memory this program will use, mostly, in advance. */
size_t const as__n0 = arg__problem.idm__n;
size_t const as__n2 = one_plus(as__n0);
size_t const as__m2 = arg__problem.idm__m;
size_t const as__m4 = double_that(as__m2);
std::vector<uint32_t> as__first(as__n2);
std::vector<uint32_t> as__array(as__m4);
std::vector<uint32_t> as__queue(as__n0);
std::vector<uint32_t> as__parent(as__n0);
// Pass the baton!
as__first.swap(arg__problem.idm__neighbours_first);
as__array.swap(arg__problem.idm__neighbours_array);
as__queue.swap(arg__problem.idm__queue);
as__parent.swap(arg__problem.idm__parent);
}
void problem_mesaj4__preprocess_neighbours_arrays__in_preparation_for_our_traversal_of_the_friendship_graph (mesaj4_type & arg__problem) {
/* Now that the memory is all acquired, precompute the two arrays to be used for traversing the friendship graph. */
size_t const as__n0 = arg__problem.idm__n;
size_t const as__m2 = arg__problem.idm__m;
std::vector<edge_type> const & as__edges = arg__problem.idm__edges;
std::vector<uint32_t> & as__first = arg__problem.idm__neighbours_first;
std::vector<uint32_t> & as__array = arg__problem.idm__neighbours_array;
// For each node u, compute its degree.
std::fill(as__first.begin(), as__first.begin() + as__n0, static_cast<uint32_t>(0));
size_t as__j = 0;
size_t as__u7 = 0;
size_t as__u8 = 0;
edge_type const * as__ep = nullptr;
for (as__j = 0; as__m2 > as__j; ++as__j) {
as__ep = &(as__edges.at(as__j));
as__u7 = static_cast<size_t>(as__ep->idm__u2);
as__u8 = static_cast<size_t>(as__ep->idm__u5);
as__first.at(as__u7) += 1;
as__first.at(as__u8) += 1; }
// Based on the degree values just computed, compute for its edge, from where we may lay out its neighbours,
// i.e. the position for its first neighbour in the shared array of neighbours, shared among all the nodes.
size_t as__count = 0;
size_t as__last = 0;
for (as__j = 0; as__n0 > as__j; ++as__j) {
as__count = static_cast<size_t>(as__first.at(as__j));
as__first.at(as__j) = static_cast<uint32_t>(as__last);
as__last += as__count; }
// Tread the array of starting positions just computed, as an array of current positions, and lay out neighbours,
// for all nodes, at once, intertwined; bookkeeping delight, also as__j used at its full potential, this code.
for (as__j = 0; as__m2 > as__j; ++as__j) {
as__ep = &(as__edges.at(as__j));
as__u7 = static_cast<size_t>(as__ep->idm__u2);
as__u8 = static_cast<size_t>(as__ep->idm__u5);
as__array.at(as__first.at(as__u7)) = static_cast<uint32_t>(as__u8);
as__first.at(as__u7) += 1;
as__array.at(as__first.at(as__u8)) = static_cast<uint32_t>(as__u7);
as__first.at(as__u8) += 1; }
// For each node u, compute its degree; repetition makes perfect!
std::fill(as__first.begin(), as__first.begin() + as__n0, static_cast<uint32_t>(0));
for (as__j = 0; as__m2 > as__j; ++as__j) {
as__ep = &(as__edges.at(as__j));
as__u7 = static_cast<size_t>(as__ep->idm__u2);
as__u8 = static_cast<size_t>(as__ep->idm__u5);
as__first.at(as__u7) += 1;
as__first.at(as__u8) += 1; }
// Based on the degree values just computed, compute for its edge, from where we may lay out its neighbours,
// i.e. the position for its first neighbour in the shared array of neighbours, shared among all the nodes.
as__last = 0;
for (as__j = 0; as__n0 > as__j; ++as__j) {
as__count = static_cast<size_t>(as__first.at(as__j));
as__first.at(as__j) = static_cast<uint32_t>(as__last);
as__last += as__count; }
// Also, store the position where the neighbours of our sentinel would start.
// We want this sentinel, to be able to easily iterate neighbours, for each node, including the last.
as__first.at(as__n0) = as__last;
}
void problem_mesaj4__determine_a_solution_if_there_exists_any_at_all (mesaj4_type & arg__problem) {
// In any one sequence of moves that manages to pass all the messages to every node, there is precisely one node y which receives all
// messages first; before y receives all its messages, from each node x, x ≠ y, there must be a step where x transmits all its messages
// to some other node x' so that x − x' is an edge in the friendship graph; similarly, after y receives all its messages,
// for each node z, z ≠ y, there must be a step when z receives its messages from some node z', such that
// z' − z is an edge in the friendship graph.
// In the light of this necessity, we see that if there exists at least one spanning tree for the whole graph,
// i.e. the graph is connected, then the problem has a solution: simply move inwardly in the spanning tree to some
// arbitrary node x, then in a second, and final, stage, simply move outwardly from the same node x, in the spanning tree,
// and at each move, pass all messages.
// To solve, we build a breadth first search traversal sequence, into a queue, while also storing for each node, its parent.
size_t const as__n0 = arg__problem.idm__n;
std::vector<uint32_t> & as__queue = arg__problem.idm__queue;
std::vector<uint32_t> & as__parent = arg__problem.idm__parent;
std::vector<uint32_t> const & as__neighbours_first = arg__problem.idm__neighbours_first;
std::vector<uint32_t> const & as__neighbours_array = arg__problem.idm__neighbours_array;
std::iota(as__parent.begin(), as__parent.end(), static_cast<uint32_t>(0));
size_t as__queue_position_insert = 0;
size_t as__queue_position_extract = 0;
as__queue.at(as__queue_position_insert) = static_cast<uint32_t>(0);
as__queue_position_insert += 1;
as__parent.at(0) = static_cast<uint32_t>(as__n0);
size_t as__u2 = 0;
size_t as__u5 = 0;
size_t as__j = 0;
size_t as__h = 0;
size_t as__cc = as__n0;
while (as__queue_position_extract < as__queue_position_insert) {
as__u2 = static_cast<size_t>(as__queue.at(as__queue_position_extract));
as__queue_position_extract += 1;
as__j = static_cast<size_t>(as__neighbours_first.at(as__u2 + 0));
as__h = static_cast<size_t>(as__neighbours_first.at(as__u2 + 1));
for (/* Non sequitur: */static_cast<void>(std::boolalpha); as__h > as__j; ++as__j) {
as__u5 = static_cast<size_t>(as__neighbours_array.at(as__j));
if (as__parent.at(as__u5) == as__u5) {
as__queue.at(as__queue_position_insert) = static_cast<uint32_t>(as__u5);
as__queue_position_insert += 1;
as__parent.at(as__u5) = static_cast<uint32_t>(as__u2);
as__cc -= 1; }}}
arg__problem.idm__cc = as__cc;
}
void problem_mesaj4__write_the_solution_or_lack_of_any_such_thing_and_be_done_with_it (mesaj4_type & arg__problem) {
std::ofstream as__os;
as__os.exceptions(std::ifstream::failbit | std::ifstream::badbit);
as__os.open("mesaj4.out");
size_t const as__cc = arg__problem.idm__cc;
if (as__cc > 1) {
as__os << -1 << '\n';
return; }
size_t const as__n0 = arg__problem.idm__n;
std::vector<uint32_t> const & as__queue = arg__problem.idm__queue;
std::vector<uint32_t> const & as__parent = arg__problem.idm__parent;
size_t as__j = 0;
size_t as__u2 = 0;
size_t as__u5 = 0;
as__os << ((as__n0 - 1) * 2) << '\n';
for (as__j = as__n0 - 1; 0 < as__j; --as__j) {
as__u5 = static_cast<size_t>(as__queue.at(as__j));
as__u2 = static_cast<size_t>(as__parent.at(as__u5));
as__os << (1 + as__u5) << ' ' << (1 + as__u2) << '\n'; }
for (as__j = 1; as__n0 > as__j; ++as__j) {
as__u5 = static_cast<size_t>(as__queue.at(as__j));
as__u2 = static_cast<size_t>(as__parent.at(as__u5));
as__os << (1 + as__u2) << ' ' << (1 + as__u5) << '\n'; }
}
void demo (void) {
mesaj4_type as__problem;
problem_mesaj4__read_the_input__all_of_it(as__problem);
problem_mesaj4__allocate_all_the_space__id_est_memory__all_of_it (as__problem);
problem_mesaj4__preprocess_neighbours_arrays__in_preparation_for_our_traversal_of_the_friendship_graph (as__problem);
problem_mesaj4__determine_a_solution_if_there_exists_any_at_all (as__problem);
problem_mesaj4__write_the_solution_or_lack_of_any_such_thing_and_be_done_with_it (as__problem);
}
void lament (std::exception const & as__exc) {
try {
std::cerr << as__exc.what() << std::endl; }
catch ( ... ) {
/* Oh, dear! */ }
}
int main (void) {
int status = 23;
try {
demo();
status = 0; }
catch (std::exception const & as__exc) {
lament(as__exc);
status = 19; }
catch ( ... ) {
status = 17; }
return status;
}