#include <iostream>
#include <string>
#include <vector>
#include <sstream>
#include <set>
#include <algorithm>

static int NowSeqS = 0;

struct StrSeq {
  std::string str;
  int index;
  StrSeq(std::string s) : str(s), index(-1) {}
};

bool operator<(StrSeq a, StrSeq b) { return a.str < b.str; }

std::ostream &operator<<(std::ostream &s, StrSeq ob) {
  s << ob.str;
  return s;
}

void set_grouping(std::vector<StrSeq> &input, std::vector<std::vector<StrSeq>> &output) {
  std::vector<std::set<StrSeq> *> sets;
  for (auto &s : input) {
    std::string g1x, g2x;
    std::stringstream ss(s.str);
    getline(ss, g1x, '=');
    getline(ss, g2x);
    StrSeq g1 = StrSeq(g1x);
    StrSeq g2 = StrSeq(g2x);
    /*-------------------------------------*/
    std::set<StrSeq> *g1_in_set = nullptr;
    std::set<StrSeq> *g2_in_set = nullptr;
    /* g1 */
    for (auto p : sets) {
      auto q = (*p).find(g1);
      if (q != (*p).end())
        g1_in_set = p;
    }
    /* g2 */
    for (auto p : sets) {
      auto q = (*p).find(g2);
      if (q != (*p).end()) {
        if (g1_in_set == p)
          continue;
        g2_in_set = p;
      }
      
    }
    /*-------------------------------------*/
    if (g1_in_set == nullptr && g2_in_set == nullptr) {
      g1.index = NowSeqS++;
      g2.index = NowSeqS++;
      std::set<StrSeq> *p = new std::set<StrSeq>();
      (*p).insert(g1);
      (*p).insert(g2);
      sets.push_back(p);
    } else if (g1_in_set != nullptr && g2_in_set == nullptr) {
      g2.index = NowSeqS++;      
      (*g1_in_set).insert(g2);
    } else if (g1_in_set == nullptr && g2_in_set != nullptr) {
      g1.index = NowSeqS++;
      (*g2_in_set).insert(g1);
    } else if (g1_in_set != g2_in_set) {
      for (auto g : *g2_in_set)
        (*g1_in_set).insert(g);
      for (auto p = sets.begin(); p != sets.end(); p++) {
        if (*p == g2_in_set) {
          sets.erase(p);
          break;
        }
      }
    }
  }
  /*-------------------------------------*/
  std::vector<StrSeq> set_contents;
  for (auto p : sets) {
    for (auto g_string : *p) { /* *p == std::set */
      set_contents.push_back(g_string);
    }
    output.push_back(set_contents);
    set_contents.clear();
  }      

  for (auto p : sets)
    delete p;
}

int main() {
  std::vector<std::string> input = {
    "a1=a2", "b1=b2", "b3=b2", "c1=c2", "e1=e2",
    "a3=a4", "c3=c4", "e1=e3", "a2=a4", "c3=c1",
    "b3=a4", "c2=d1", "a4=a5", "d2=c1", "b4=b3", "d3=c3" };
  std::vector<std::vector<StrSeq>> output;

  std::vector<StrSeq> input2;
  for (auto s : input)
    input2.push_back(StrSeq(s));

  set_grouping(input2, output);

  for (auto &v : output) {
    sort(v.begin(), v.end(), [](auto const &lhs, auto const &rhs) {
      return lhs.index < rhs.index;
    });
    std::cout << "{ ";
    for (auto s : v) {
      std::cout << "\"" << s << "\", ";
    }
    std::cout << "}" << std::endl;
  }
  return 0;
}
/* end */
