#include <cstddef>
#include <exception>
#include <fstream>
#include <iostream>
#include <limits>
#include <string>
#include <string_view>
#include <unordered_map>
#include <unordered_set>
class TripletWordAdapter
{
public:
class TripletWordIterator
{
public:
TripletWordIterator(const std::string_view word, const std::size_t position)
: m_word(word)
, m_position(position)
{
if (m_word.length() <= 4)
throw std::logic_error("The word is too short to iterate through");
}
std::pair<std::string_view, std::string_view> operator*() const
{
if (m_position + 4 > m_word.length())
throw std::logic_error("Iterator is out of a valid range");
return std::pair(m_word.substr(m_position, 3),
m_word.substr(m_position + 1, 3));
}
TripletWordIterator& operator++()
{
++m_position;
if (m_position > m_word.length() - 3)
throw std::logic_error("Iterator is out of a valid range");
return *this;
}
bool operator!=(const TripletWordIterator other) const
{
return m_position != other.m_position;
}
private:
const std::string_view m_word;
std::size_t m_position;
};
TripletWordAdapter(std::string_view word)
: m_word(word)
{
if (m_word.length() < 4)
throw std::logic_error("Can't wrap a word too short to iterate through");
}
TripletWordIterator begin() const { return TripletWordIterator(m_word, 0); }
TripletWordIterator end() const
{
return TripletWordIterator(m_word, m_word.length() - 3);
}
private:
const std::string_view m_word;
};
class WordGraphSolver
{
public:
void ProcessWord(const std::string_view word)
{
for (auto [from, to] : TripletWordAdapter(word)) {
if (from.compare(to) < 0)
std::swap(from, to);
if (++m_edges[std::string(from) + ' ' + std::string(to)] != 1)
continue;
// A new edge have appeared, meaning a new vertex has been added to a
// graph
m_vertices.emplace(from);
m_vertices.emplace(to);
}
}
void PrintResults() const
{
std::cout << m_vertices.size() << std::endl;
std::cout << m_edges.size() << std::endl;
for (const auto& [edge, weight] : m_edges)
std::cout << edge << ' ' << weight << std::endl;
}
private:
std::unordered_set<std::string> m_vertices;
std::unordered_map<std::string, std::uint32_t> m_edges;
};
int
main()
{
std::ifstream input("input.txt");
input.ignore(std::numeric_limits<std::streamsize>::max(), '\n');
WordGraphSolver solver;
std::string line;
while (std::getline(input, line))
solver.ProcessWord(line);
solver.PrintResults();
}