isspngtree.cpp
// $Id$
/* COMIENZO DE DESCRIPCION
__USE_WIKI__
Dado un grafo #G#, y un arbol #T#, decimos que #T# "expande" a
#G# si la raiz #n# de #T# es un vertice de #G#, y los caminos de
#T# permiten llegar desde #n# hasta cualquier otro nodo de #G#.
Escribir una funcion #bool is_spng_tree(G,T)# (por
"is-spanning-tree") que determina si #T# expande a #G#.
[Tomado en el 3er parcial del 2009-11-27].
keywords: conjunto, correspondencia
FIN DE DESCRIPCION */
// -------------------------------------------------------------------
#include <cstdarg>
#include <cstdio>
#include <iostream>
#include <map>
#include <set>
#include <algorithm>
#include "./util.h"
#include "./tree.h"
#include "./util_tree.h"
using namespace aed;
using namespace std;
typedef map<int,set<int> > graph_t;
// Primero escribimos una tree_nodeset(tree<int> &T,set<int>
// &nodeset); que retorna true si todos los nodos de T son
// distintos y si ese es el caso retorna por !+nodeset+ el
// conjunto de nodos de !+T+. \emph{Ayuda:} Probablemente
// esto requiere hacerlo en forma recursiva sobre el arbol.
//
// Despues escribimos una funcion !+void
// graph_vrtxset(map<int,set<int>> &G,set<int> &vrtxset);+
// que retorna por !+vrtxset+ el conjunto de vertices de
// !+G+.
//
// Finalmente con la ayuda de las dos funciones auxiliares
// previas: 1) Comprobar que los nodos de !+T+ son
// unicos. (esto lo hace tree_nodeset). 2) Comprobar que el
// conjunto de nodos de !+T+ es igual al de vertices de
// !+G+. 3) Verificar que las aristas de !+T+ (es
// decir los pares padre-hijo) estan contenidos en
// !+G+. Para esto escribimos una funcion recursiva
// sobre el arbol check_edges(...)
//---:---<*>---:---<*>---:---<*>---:---<*>---:---<*>
bool tree_nodeset(tree<int> &T,tree<int>::iterator n,
set<int> &nodeset) {
if (nodeset.find(*n)!=nodeset.end()) return false;
nodeset.insert(*n);
tree<int>::iterator q = n.lchild();
while (q!=T.end())
if (!tree_nodeset(T,q++,nodeset)) return false;
return true;
}
//---:---<*>---:---<*>---:---<*>---:---<*>---:---<*>
// Wrapper
bool tree_nodeset(tree<int> &T,set<int> &nodeset) {
nodeset.clear();
if (T.begin()==T.end()) return true;
return tree_nodeset(T,T.begin(),nodeset);
}
//---:---<*>---:---<*>---:---<*>---:---<*>---:---<*>
void graph_vrtxset(graph_t &G,set<int> &vrtxset) {
vrtxset.clear();
graph_t::iterator q = G.begin();
while (q!=G.end()) vrtxset.insert(q++->first);
}
//---:---<*>---:---<*>---:---<*>---:---<*>---:---<*>
bool check_edges(graph_t &G,tree<int> &T,
tree<int>::iterator p) {
// Verifica si los hijos de `p' estan conectados
// por `G'
if (p==T.end()) return true;
// Este es el conjunto de vecinos de `p' en el grafo
set<int> &ngbrs = G[*p];
tree<int>::iterator q = p.lchild();
while (q!=T.end())
// Verifica que `p' y `q' sean vecinos
// en el grafo y ademas lo aplica recursivamente.
if (ngbrs.find(*q++)==ngbrs.end()
|| !check_edges(G,T,q)) return false;
return true;
}
//---:---<*>---:---<*>---:---<*>---:---<*>---:---<*>
bool is_spng_tree(graph_t &G,tree<int> &T) {
set<int> nodeset, vrtxset;
if (!tree_nodeset(T,nodeset)) return false;
graph_vrtxset(G,vrtxset);
if (nodeset!=vrtxset) return false;
return check_edges(G,T,T.begin());
}
//---:---<*>---:---<*>---:---<*>---:---<*>---:---<*>
// Esta es una segunda version que no usa funciones
// auxiliares, para esto solo usa un argumento auxiliar
// set<int> visited que trackea los nodos a medida que va
// recorriendo el arbol. De esta forma se hacen todos los
// chequeos al mismo tiempo.
bool is_spng_tree2(graph_t &G,tree<int> &T,
tree<int>::iterator n,set<int> &visited) {
// `n' ya fue visitado, asi que el arbol pasa dos veces
// por el mismo nodo
if (visited.find(*n)!=visited.end()) return false;
visited.insert(*n);
// Verifica que el nodo este en el grafo.
// Si el nodo no tiene vecinos en el grafo
// la entrada deberia estar, apuntando al
// conjunto vacio.
if (G.find(*n)==G.end()) return false;
// Verifica que cada hijo de n este en su lista de
// vecinos
tree<int>::iterator c = n.lchild();
set<int> &n_ngbrs = G[*n];
while (c!=T.end())
if (n_ngbrs.find(*c++)==n_ngbrs.end()) return false;
// Verifica que el subarbol de cada uno de los
// `c' este contenido en `G'
c = n.lchild();
while (c!=T.end())
if (!is_spng_tree2(G,T,c++,visited))
return false;
return true;
}
//---:---<*>---:---<*>---:---<*>---:---<*>---:---<*>
// Wrapper
bool is_spng_tree2(graph_t &G,tree<int> &T) {
printf("T size: %d\n",T.size());
if (T.size()!=G.size()) return false;
if (T.begin()==T.end()) return true;
set<int> visited;
return is_spng_tree2(G,T,T.begin(),visited);
}
//---:---<*>---:---<*>---:---<*>---:---<*>---:---<*>
void graph_print(graph_t &G) {
graph_t::iterator q = G.begin();
while (q!=G.end()) {
printf("G[%d]: ",q->first);
set<int> &qngbrs = q->second;
set<int>::iterator r = qngbrs.begin();
while (r!=qngbrs.end())
printf("%d ",*r++);
printf("\n");
q++;
}
}
//#define is_spng_tree is_spng_tree2
//---:---<*>---:---<*>---:---<*>---:---<*>---:---<*>
#define BP -1
#define EP -2
#define TERM -3
int main() {
// Load Graph
graph_t G;
// 0---1---2
// | | |
// 3---4---5
// | | |
// 6---7---8
add_to_set(G[0],TERM,1,3,TERM);
add_to_set(G[1],TERM,0,2,4,TERM);
add_to_set(G[2],TERM,1,5,TERM);
add_to_set(G[3],TERM,0,4,6,TERM);
add_to_set(G[4],TERM,1,3,5,7,TERM);
add_to_set(G[5],TERM,2,4,8,TERM);
add_to_set(G[6],TERM,3,7,TERM);
add_to_set(G[7],TERM,4,6,8,TERM);
add_to_set(G[8],TERM,5,7,TERM);
graph_print(G);
printf("\n\n");
// Load tree starting at 0, breadth-first
// (0 (1 (2 5) (4 (7 8))) (3 6))
tree<int> T;
list2treev(T,TERM,BP,EP,
BP,0,BP,1,BP,2,5,EP,BP,4,BP,7,8,EP,
EP,EP,BP,3,6,EP,EP,TERM);
printf("T: ");
T.lisp_print();
printf("\nis T a spanning tree for G? : %d\n\n",
is_spng_tree(G,T));
// Load tree traverse like list, starting as 0
// (0 (1 (2 (5 (4 (3 (6 (7 (8)))))))))
T.clear();
list2treev(T,TERM,BP,EP,
BP,0,BP,1,BP,2,BP,5,BP,4,BP,3,BP,
6,BP,7,BP,8,EP,EP,EP,EP,EP,EP,EP,EP,EP,TERM);
printf("T: ");
T.lisp_print();
printf("\nis T a spanning tree for G? : %d\n\n",
is_spng_tree(G,T));
// Load tree (should fail, because 4 is not connected to 0
// (0 (3 6) (4 7 (5 8)) (1 2))
T.clear();
list2treev(T,TERM,BP,EP,
BP,0,BP,3,6,EP,BP,4,7,BP,5,8,EP,EP,BP,1,2,EP,EP,TERM);
printf("T: ");
T.lisp_print();
printf("\nis T a spanning tree for G? : %d\n\n",
is_spng_tree(G,T));
return 0;
}
Generated by GNU Enscript 1.6.6.