Cod sursa(job #2866221)

Utilizator the_horoHorodniceanu Andrei the_horo Data 9 martie 2022 14:27:46
Problema Ciclu Eulerian Scor 80
Compilator cpp-64 Status done
Runda Arhiva educationala Marime 3.82 kb
#include <algorithm>
#include <array>
#include <cstdint>
#include <forward_list>
#include <fstream>
#include <iostream>
#include <iterator>
#include <vector>


/* Defines */
using i32 = int32_t;
using u32 = uint32_t;

using Edges = std::vector<std::vector<std::pair<size_t, u32>>>; // [node] -> [toNode, edgeIndex];

constexpr const char *inputFilename = "ciclueuler.in";
constexpr const char *outputFilename = "ciclueuler.out";

constexpr u32 MAX_EDGES = 500000;


/* Function definitions */
Edges readInput();
bool allNodesHaveEvenDegree(const Edges &graph);

std::forward_list<size_t> findEulerianCycle(const Edges &edges);
void useCycle(const size_t start, const Edges &edges, std::array<bool, MAX_EDGES>& usedEdge,
              std::forward_list<size_t> &result, std::forward_list<size_t>::iterator journal);

void removeUnusedEdges(Edges::value_type &toEdges, const std::array<bool, MAX_EDGES>& usedEdge);

void writeNoAnswer();
void writeResult(const std::forward_list<size_t> &result);


/* Global variables */


/* Function declarations */
Edges readInput () {
    std::ifstream file(inputFilename);
    file.exceptions(file.badbit | file.eofbit | file.failbit);

    size_t nodesCount;
    u32 edgeCount;
    file >> nodesCount >> edgeCount;

    Edges edges(nodesCount);

    for (u32 edge = 0; edge != edgeCount; ++ edge) {
        size_t from, to;
        file >> from >> to;
        -- from, -- to;

        edges[from].emplace_back(to, edge);
        edges[to].emplace_back(from, edge);
    }

    return edges;
}

bool allNodesHaveEvenDegree (const Edges &graph) {
    std::vector<bool> parityOfDegree(graph.size());

    for (size_t i = 0; i != graph.size(); ++ i)
        for (auto [j, _]: graph[i]) {
            if (i <= j) {
                parityOfDegree[i] = !parityOfDegree[i];
                parityOfDegree[j] = !parityOfDegree[j];
            }
        }

    return std::all_of(parityOfDegree.begin(), parityOfDegree.end(), [](auto x){ return x == false; });
}

std::forward_list<size_t> findEulerianCycle (const Edges &ogEdges) {
    std::forward_list<size_t> result({0});
    Edges edges = ogEdges;

    std::array<bool, MAX_EDGES> usedEdge({});

    for (auto it = result.begin(); it != result.end();) {
        removeUnusedEdges(edges[*it], usedEdge);

        if (edges[*it].empty()) {
            ++ it;
            continue;
        }

        useCycle(*it, edges, usedEdge, result, it);
    }

    return result;
}

void useCycle (const size_t start, const Edges &edges, std::array<bool, MAX_EDGES>& usedEdge,
               std::forward_list<size_t> &result, std::forward_list<size_t>::iterator journal) {
    size_t node = start;
    do {
        for (auto [toNode, edgeIndex]: edges[node])
            if (!usedEdge[edgeIndex]) {
                usedEdge[edgeIndex] = true;

                node = toNode;

                journal = result.emplace_after(journal, node);

                break;
            }
    } while (node != start);
}

void removeUnusedEdges (Edges::value_type &toEdges, const std::array<bool, MAX_EDGES>& usedEdge) {
    Edges::value_type unused;
    for (auto [toNode, edgeIndex]: toEdges)
        if (!usedEdge[edgeIndex])
            unused.emplace_back(toNode, edgeIndex);
    toEdges = unused;
}

void writeNoAnswer () {
    std::ofstream output(outputFilename);
    output.exceptions(output.badbit | output.eofbit | output.failbit);

    output << "-1\n";
}

void writeResult (const std::forward_list<size_t> &result) {
    std::ofstream output(outputFilename);
    output.exceptions(output.badbit | output.eofbit | output.failbit);

    for (auto it = std::next(result.begin()); it != result.end(); ++ it)
        output << *it + 1 << ' ';
    output.put('\n');
}


int main () {
    const Edges edges(readInput());

    if (!allNodesHaveEvenDegree(edges))
        writeNoAnswer();
    else
        writeResult(findEulerianCycle(edges));
}