Cod sursa(job #2866228)

Utilizator the_horoHorodniceanu Andrei the_horo Data 9 martie 2022 14:39:39
Problema Ciclu Eulerian Scor 80
Compilator cpp-64 Status done
Runda Arhiva educationala Marime 3.74 kb
#include <algorithm>
#include <array>
#include <cassert>
#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 consumeCycle(const size_t start, Edges &edges, std::array<bool, MAX_EDGES>& usedEdge,
                  std::forward_list<size_t> &result, std::forward_list<size_t>::iterator journal);

void dropBackUsedEdges(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();) {
        dropBackUsedEdges(edges[*it], usedEdge);
        if (edges[*it].empty()) {
            ++ it;
            continue;
        }

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

    return result;
}

void consumeCycle(const size_t start, 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 {
        dropBackUsedEdges(edges[node], usedEdge);

        auto [toNode, edgeIndex] = edges[node].back();
        edges[node].pop_back();

        usedEdge[edgeIndex] = true;

        node = toNode;

        journal = result.emplace_after(journal, node);
    } while (node != start);
}

void dropBackUsedEdges (Edges::value_type &toEdges, const std::array<bool, MAX_EDGES>& usedEdge) {
    while (!toEdges.empty() && usedEdge[toEdges.back().second])
        toEdges.pop_back();
}

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));
}