// Chemin Eulérien - Algorithme de Fleury // https://www.geeksforgeeks.org/fleurys-algorithm-for-printing-eulerian-path/ #include #include #include #include #include using namespace std; // Classe pour un graphe non orienté class Graph { private: int V; // nombre de sommets list *adj; // liste d'adjacences public: Graph(int _V) : V(_V) { adj = new list[V]; } // constructeur ~Graph() { delete[] adj; } // destructeur // Ajouter une arête void addEdge(const int u, const int v) { adj[u].push_back(v); adj[v].push_back(u); } void rmvEdge(const int u, const int v); void printEulerTour(); // tour Eulérien void printEulerUtil(const int s); // Nombre de sommets atteignables à partir de v (DFS) int DFSCount(const int v, vector &visited); // Vérifier si une arête u-v peut être ajoutée au chemin Eulérien bool isValidNextEdge(const int u, const int v); }; void Graph::printEulerTour() { // Trouver un sommet de degré impair int u = 0; for(int i = 0; i < V; i++) if(adj[i].size() & 1) { u = i; break; } printEulerUtil(u); cout << '\n'; } // printEulerTour() // Tour Eulérien depuis le sommet u void Graph::printEulerUtil(const int u) { // Récursivité sur tous les sommets adjacents à u for(auto it = adj[u].begin(); it != adj[u].end(); it++) { int v = *it; // Si l'arête u-v est valide if(v != -1 && isValidNextEdge(u, v)) { cout << u << '-' << v << ' '; rmvEdge(u, v); printEulerUtil(v); } } } // printEulerUtil() // Vérifier si une arête u-v peut être considérée dans le tour Eulérien bool Graph::isValidNextEdge(int u, int v) { // Une arête u-v est valide dans l'un des deux cas suivants : // 1. v est le seul sommet adjacent à u int count = 0; // pour compter les sommets adjacents for(auto it = adj[u].begin(); it != adj[u].end(); it++) if(*it != -1) count++; if(count == 1) return true; // 2. S'il y a plusieurs sommets adjacents à u, alors u-v n'est pas un pont // Si u-v est un pont : // 2.a. Compter les sommets atteignables depuis u vector visited(V, false); int count1 = DFSCount(u, visited); // 2.b. Ôter u-v du graphe puis compter les sommets atteignables depuis u rmvEdge(u, v); fill(visited.begin(), visited.end(), false); int count2 = DFSCount(u, visited); // 2.c. Ajouter u-v de nouveau dans le graphe addEdge(u, v); // 2.d. Si count1 est plus grand, alors u-v est un pont return (count1 > count2) ? false : true; } // isValidNextEdge() // Ôter l'arête u-v du graphe. Remplace le sommet adjacent par -1. void Graph::rmvEdge(const int u, const int v) { // Chercher v dans la liste d'adjacence de u et le remplacer par -1 : auto iv = find(adj[u].begin(), adj[u].end(), v); *iv = -1; // Chercher u dans la liste d'adjacence de v et le remplacer par -1 : auto iu = find(adj[v].begin(), adj[v].end(), u); *iu = -1; } // rmvEdge() // A DFS based function to count reachable vertices from v int Graph::DFSCount(const int v, vector &visited) { visited[v] = true; // marquer v comme visité int count = 1; // Récursivité sur tous les sommets adjacents à v for(int adj : adj[v]) if(adj != -1 && !visited[adj]) count += DFSCount(adj, visited); return count; } // DFSCount() // Programme principal int main() { int V, A; cin >> V >> A; // sommets, arcs Graph graphe(V); int x, y; for(int k = 0; k < A; k++) { cin >> x >> y; graphe.addEdge(x, y); } graphe.printEulerTour(); return 0; } // main()