A partir du Manuel de conception algorithme, 2ème édition, question 5-22:Supprimer degré deux sommets d'un graphe non orienté (Skiena TADM 5-22)
Concevoir un algorithme temps linéaire pour éliminer chaque sommet v degré 2 à partir d'un graphique en remplaçant les bords (u, v) et (v, w) par un bord (u, w). Nous cherchons également à éliminer plusieurs copies d'arêtes en les remplaçant par un seul arête. Notez que la suppression de plusieurs copies d'une arête peut créer un nouveau sommet de degré 2, qui doit être supprimé, et que la suppression d'un sommet de degré 2 peut créer plusieurs arêtes, qui doivent également être supprimées.
Parce que la question apparaît dans la section sur les graphes non orientés, supposer que notre graphe est non orienté.
Voici un algorithme permettant de supprimer les sommets de degré deux comme souhaité, similaire à celui donné here. L'implémentation repose sur les structures de graphe, de file d'attente et d'édgenode de Skiena. g-> edges [v] est un pointeur vers la tête de la liste d'adjacence de v. g-> M [u] [v] renvoie la valeur booléenne dans la ligne u et la colonne v de la matrice d'adjacence de g. Le problème: selon mon analyse, cela ne fonctionne pas en temps linéaire, que nous utilisions des listes d'adjacence ou des matrices d'adjacence pour représenter notre graphe.
process_vertex(graph *g, int v, queue Q) {
int u,w;
if (degree[v] != 2) {return;}
u = pop_first_edge(g,v); // O(n) for AL, O(n) for AM
w = pop_first_edge(g,v); // O(n) for AL, O(n) for AM
if (!edge_exists(g,u,w)) { // O(n) for AL, O(1) for AM
insert_edge(g,u,w);
}
if (degree[u] == 2) {enqueue(Q,u);}
if (degree[w] == 2) {enqueue(Q,w);}
}
remove_degree_twos(graph *g) {
queue Q;
for (int v = 1; v <= g->nvertices; ++v) {
if (degree[v] == 2) {enqueue(Q,v);}
}
while (!Q.empty()) {
process_vertex(g,dequeue(Q),Q);
}
}
Il y a deux fonctions nécessaires qui n'ont pas encore été mises en œuvre:
// removes the first edge in v's adjacency list
// and updates degrees appropriately
// returns the vertex to which that edge points
int pop_first_edge(g,v);
// determines whether edge (u,v) already exists
// in graph g
bool edge_exists(g,u,v);
Si g est représenté avec des listes de contiguïté, peut alors être mis à exécution les fonctions requises comme suit:
// O(n)
int pop_first_edge(g,v) {
int u = -1; // the vertex to which the first outedge from v points
edgenode *p = g->edges[v];
if (p != NULL) {
u = p->y;
g->edges[v] = p->next;
--(g->degree[v]);
// delete v from u's adjacency list
p1 = &g->edges[u];
p2 = g->edges[u];
while (p2 != NULL) {
if (p2->y == v) {
*p1 = p2->next;
--(g->degree[u]);
break;
}
p1 = p2;
p2 = p2->next;
}
}
}
// O(n)
edge_exists(g,u,w) {
edgenode *p = g->edges[u];
while (p != NULL) {
if (p->y == w) {
return true;
}
p = p->next;
}
return false;
}
Si g est représenté avec des matrices d'adjacence, alors nous avons:
// O(n)
int pop_first_edge(v) {
int u = -1;
for (int j = 1; j <= g->nvertices; ++j) {
if (M[v][j]) {
u = j;
break;
}
}
if (u > 0) {
M[v][u] = false;
M[u][v] = false;
--(g->degree[v]);
--(g->degree[u]);
return u;
} else {
return -1;
}
}
// O(1)
edge_exists(g,u,w) {
return g->M[u][w];
}
Que nous utilisions des listes d'adjacence ou des matrices d'adjacence, l'exécution de process_vertex est O (n), où n est le nombre de sommets dans le graphe. Comme les sommets O (n) peuvent être traités, le temps d'exécution total est O (n^2).
Comment cela peut-il être fait en temps linéaire?
De vos commentaires, je suppose que c'est un simple graphe non orienté - ie pas multi-bords ou arêtes en boucle - et si la réduction du graphe crée ces arêtes alors les arêtes existantes sont enlevées sans remplacement? – MT0
Si le graphique a un cycle: '{(1,2), (2,3), (3,2)}' à quoi le graphique devrait-il être réduit? – MT0
Voulez-vous dire {(1,2), (2,3), (3,1)}? Puisque le graphique n'est pas dirigé, (2,3) et (3,2) sont le même bord - ou plutôt, selon l'implémentation de skiena, l'un est présent si l'autre l'est également. – Chad