tpl2r20151022.cpp
#include "eval.hpp"
#include <climits>
#include <cstdlib>
#include <stack>
/* COMIENZO DE DESCRIPCION
__USE_WIKI__
#tree2count:# Dado un arbol #T# conntruye una lista #L#
que contiene en preorder la cantidad de nodos de cada
subarbol de #T#. E.g. #T=(3 (2 1 5) (7 8))# da #L=(6 3 1 1 2 1)#.
Decimos que #T# es un arbol de conteo si en los nodos tiene la
cantidad de nodos de su subarbol.
#count2tree:# Es la inversa de #tree2count#, dada la lista de
conteo reconstruye el arbol. No recupera los valores de los
nodos del arbol sino que en los nodos quedan las conteos de hijos.
E.g. #L=(6 3 1 1 2 1)#. #T=(6 (3 1 1) (2 1))#.
Notemos que #count2tree(tree2count(count2tree(T)))=count2tree(T)#.
Es decir #count2tree# es la inversa de #tree2count# asumiendo que #T#
ya es un arbol de conteo.
#hasnpath:# Dado un grafo #G#, dos vertices #a,b#, y un entero #n>=0#
determina si existe un camino (con posibles nodos repetidos) de
longitud #n# de #a# a #b#.
#key2abbrev:# Dado una serie de strings #keys# encontrar para cada
uno de ellos un prefijo unico #abb# lo mas corto posible. Por ejemplo
#(mesa metro multa) -> (me met m)#.
[Tomado en el Recup Trabajo Practico de Laboratorio Nro 2
(TPL2R) de 2015-10-22].
keywords: arbol orientado, grafo, correspondencia
FIN DE DESCRIPCION */
using namespace aed;
using namespace std;
typedef tree<int>::iterator node_t;
typedef tree<int>::const_iterator cnode_t;
//---:---<*>---:---<*>---:---<*>---:---<*>---:---<*>
// TREE2COUNT: version 1, como se explica en la ayuda del TPL.
// Por composicion de mkcount y preorder
void mkcount(tree<int> &T,node_t n) {
node_t c = n.lchild();
int ncount =1;
while (c!=T.end()) {
// Aplica recursivamente mkcount a los hijos
mkcount(T,c);
// Acumula el count de n
ncount += *c++;
}
// Pisa el valor de n
*n = ncount;
}
//---:---<*>---:---<*>---:---<*>---:---<*>---:---<*>
// listado en preorder
void preorder(tree<int> &T,tree<int>::iterator n,list<int> &L) {
L.insert(L.end(),*n);
tree<int>::iterator c = n.lchild();
while (c!=T.end()) {
preorder(T,c,L);
c = c.right();
}
}
//---:---<*>---:---<*>---:---<*>---:---<*>---:---<*>
// No se hacen wrappers para mkcount y preorder ya que
// las usamos internameente en tree2count
void tree2count(tree<int> &T,list<int> &L) {
mkcount(T,T.begin());
preorder(T,T.begin(),L);
}
//---:---<*>---:---<*>---:---<*>---:---<*>---:---<*>
// Version 2: Lo hace directamente de una sola pasada en T,
// De yapa no modifica a T, por lo tanto lo podemos declarar como const.
// retorna por Ln la lista de los count del subarbol de n (en preorder)
void tree2count2(const tree<int> &T,
cnode_t n,list<int> &Ln) {
if (n==T.end()) return;
// Este valor del frente corresponde a n, por ahora
// lo ponemos en 1 pero despues vamos a ir acumulando
Ln.push_back(1);
cnode_t c = n.lchild();
while (c!=T.end()) {
// Esta es la lista de c
list<int> Lc;
// Aplica recursivamente
tree2count2(T,c++,Lc);
// Acumula en el primer elemento (corresponde a n)
Ln.front() += Lc.front();
// Splicea todo Lc al final de Ln
Ln.splice(Ln.end(),Lc);
}
}
//---:---<*>---:---<*>---:---<*>---:---<*>---:---<*>
// Wrapper
void tree2count2(tree<int> &T,list<int> &L) {
tree2count2(T,T.begin(),L);
}
//---:---<*>---:---<*>---:---<*>---:---<*>---:---<*>
// Version 1: No usa listas auxiliares para Lc
node_t count2tree(list<int> &L,tree<int> &T,node_t n) {
if (L.empty()) return n;
int count = L.front();
L.pop_front();
n = T.insert(n,count); count--;
node_t c = n.lchild();
while (count>0) {
count -= L.front();
c = count2tree(L,T,c);
c++;
}
assert(count==0);
return n;
}
//---:---<*>---:---<*>---:---<*>---:---<*>---:---<*>
void count2tree(list<int> &L,tree<int> &T) {
count2tree(L,T,T.begin());
}
//---:---<*>---:---<*>---:---<*>---:---<*>---:---<*>
node_t count2tree2(list<int> &L,tree<int> &T,node_t n) {
int count = L.front();
L.pop_front();
n = T.insert(n,count);
node_t c = n.lchild();
while (!L.empty()) {
int ccount = L.front();
list<int> Lc;
for (int j=0; j<ccount; j++) {
Lc.push_back(L.front());
L.pop_front();
}
c = count2tree2(Lc,T,c);
c++;
}
return n;
}
//---:---<*>---:---<*>---:---<*>---:---<*>---:---<*>
// Version 1: Usa una lista auxiliar para Lc
void count2tree2(list<int> &L,tree<int> &T) {
count2tree2(L,T,T.begin());
}
//---:---<*>---:---<*>---:---<*>---:---<*>---:---<*>
bool hasnpath(map<int,list<int> >&M, int a, int b, int n){
if(M.find(a)==M.end()) return false;
// Corta la recursion
if(n==0) return (a==b);
// Recorre los vecinos de `a' y chequea si alguno tiene
// un camino de longitud n-1 con `b'
list<int> &L = M[a];
for(list<int>::iterator it=L.begin();it!=L.end();it++){
if(hasnpath(M, *it, b, n-1)) return true;
}
return false;
}
//---:---<*>---:---<*>---:---<*>---:---<*>---:---<*>
void key2abbrev(map<string,string> &abbrevs) {
// Este auxiliar contendra al final la inversa de abbrevs
map<string,string> abb2key;
// Recorre las asignaciones de abbrevs
map<string,string>::iterator q = abbrevs.begin();
while (q!=abbrevs.end()) {
// Clave
const string &key = q->first;
// Longitud de la clave
int sz = key.size();
// Va probando con todos los prefijos de longitud 1 a sz
// hasta encontrar uno que no haya sido asignado
for (int len = 1; len<=sz; len++) {
// Prefijo de longitud len
string abbrev = key.substr(0,len);
// Se fija si ya fue asignado
if (abb2key.find(abbrev)==abb2key.end()) {
// No fue asignado. Lo carga en abbrevs y en abb2key
q->second = abbrev;
// cout << "key,abbrev " << key << " " << abbrev << endl;
abb2key[abbrev] = key;
break;
}
}
q++;
}
// Esto deberia ser verdad ya que fuimos chequeando que
// las abbrevs eran unicas
assert(abbrevs.size()==abb2key.size());
}
int main() {
Eval ev;
int vrbs = 0;
int seed = 123;
int h1=0,h2=0,h3=0,h4=0;
ev.eval1(tree2count,vrbs);
h1 = ev.evalr1(tree2count,seed,vrbs);
ev.eval2(count2tree,vrbs);
h2 = ev.evalr2(count2tree,seed,vrbs);
ev.eval3(hasnpath,vrbs);
h3 = ev.evalr3(hasnpath,seed,vrbs);
ev.eval4(key2abbrev,vrbs);
h4 = ev.evalr4(key2abbrev,seed,vrbs);
// Para S=123 debe dar -> H1=626 H2=303 H3=334 H4=512
printf("S=%03d -> H1=%03d H2=%03d H3=%03d H4=%03d\n",
seed,h1,h2,h3,h4);
return 0;
}
Generated by GNU Enscript 1.6.6.