#pragma once #include #include #include #include #include #include #include #include #include "aux.cpp" using namespace std; /** * @brief Struct that represents an edge in the graph * * @param from: the starting node of the edge * @param to: the ending node of the edge * @param weight: the weight of the edge * */ struct Edge { string from, to; int weight; // void print() { // cout << from << " --> " << to << " w: " << weight << endl; // } }; /** * @brief Function that compares two edges based on their weight * * @param e1: the first edge * @param e2: the second edge * @return true if the weight of e1 is greater than the weight of e2, false otherwise */ bool compareEdge(Edge e1, Edge e2) { return (e1.weight > e2.weight); } /** * @brief Class that represents an undirected weighted graph * * @param AdjList: the adjacency list of the graph * * @details The class provides methods to add edges to the graph, to check if a combination of edges is valid and to find a solution to the problem * */ class UndirectedWeightedGraph { private: void addWeightedEdge(string from, string to, int weight) { for (Edge& edge : AdjList[from]) { if (to == edge.to) { edge.weight += weight; return; } } Edge newEdge; newEdge.from = from; newEdge.to = to; newEdge.weight = weight; AdjList[from].push_back(newEdge); } public: unordered_map> AdjList; void addEdge(string node1, string node2) { addWeightedEdge(node1, node2, 1); addWeightedEdge(node2, node1, 1); } // void print() { // for (auto& pair : AdjList) { // for (Edge& edge : pair.second) { // edge.print(); // } // } // } /** * @brief Function that checks if a combination of edges is valid * * @param star: the combination of edges to check * @return true if the combination is valid, false otherwise * * @details The function checks if the intersection of the sets of nodes reachable from the nodes of the edges in the combination is a singleton * */ bool checkComb(vector star) { auto it = star.begin(); auto v = AdjList[(*it).to]; unordered_set acc; for (auto& e : v) { acc.insert(e.to); } it++; for (; it != star.end(); it++) { auto v = AdjList[(*it).to]; unordered_set s; for (auto& e : v) { s.insert(e.to); } acc = intersectSets(acc,s); } return acc.size() == 1; } /** * @brief Function that finds a solution to the problem * * @param c: the number of solutions to find * @param k: the number of edges in the solution * @param seed: the seed for the random number generator * @return a vector of vectors of edges, each vector of edges represents a solution * * @details The function iterates over the keys of the adjacency list, shuffles them, and, for each key, it sorts the edges by weight and tries all the combinations of k edges. * If a combination is valid, it is added to the solution vector */ vector> findSol(int c, int k, long seed) { vector> Sol; vector keys = getShuffleKeys(AdjList, seed); for (auto& key : keys) { auto edges = AdjList[key]; if (c == 0) break; if (edges.size() >= k) { sort(edges.begin(), edges.end(), compareEdge); vector indices(k); iota(indices.begin(), indices.end(), 0); // Fill indices with 0, 1, 2, ..., k - 1 do { vector subV; for (int i : indices) subV.push_back(edges[i]); if (checkComb(subV)) { c--; Sol.push_back(subV); break; } } while(!nextComb(indices, edges.size())); } } return Sol; } void printSol(vector> Sol) { for (auto& edges : Sol) { cout << edges[0].from << ":" << " "; for (auto& edge : edges) { cout << edge.to << " "; } cout << endl; } } };