Foro de elhacker.net

Programación => Programación C/C++ => Mensaje iniciado por: KINGARZA en 27 Julio 2016, 09:43 am



Título: ¿Mejor algoritmo? Problema con aproximaciones de Grafos
Publicado por: KINGARZA en 27 Julio 2016, 09:43 am
Hola que tal a todos!!
llevo horas quemandome la cabeza y aun no encuetro una solucion optima para este problema, podras ayudarme? te lo agradeceria mucho.

este es el problema:
Amigos Interactivos

      Límite de memoria   128MB
                Límite de tiempo (caso)   1s   
                Límite de tiempo (total)   60s
Existe una serie de personas definidas en un espacio, dichas personas tienen la capacidad nata de comuncarse entre ellas y formar relaciones sociales, sin embargo hay relaciones muy especiales que dicen llamarce amistad, dichos individuos son conciderados amigos si realizan algun tipo de saludo especial. Una empresa de analisis de comportamiento humano te ha pedido que les ayudes a saber si un individuo A es amigo de un individuo B., un dato curioso es que si existen tres invidividuos A, C, B pertenecientes al espacio, y A es amigo de C y C amigo de B, se genera un lazo mistico mediante el cual A y B son amigos, aunque pudieren no conocerse.

Problema

Dada una descripcion de los sucesos que existen durante la estancia de N individuos en un espacio definido, responder secuencialmente a las preguntas fornuladas, de manera tal que se sepa si en algun momento un indiviuo es amigo del otro.

Entrada

Un unico numero N indicando la cantidad de Individuos

Un numero M indicando la cantidad de preguntas o sucesos que acontecen

Las siguientes M lineas contendran una letra 'P' seguida de dos enteros A y B de tal modo que se debera saber si A es amigo de B en base a los saludos que hallan sido registrados hasta el momento, en caso contrario, una letra 'S' seguida de dos numero A y B indicando que el individuo Ase ha saludado con el individuo B

Ejemplo:
Entrada   Salida
5 8  
 S 1 2  
 S 2 3  
 P 2 4  
 S 4 5  
 P 5 3  
 S 5 1  
 P 2 4  
 P 5 3
Salida

Un numero en una linea por cada pregunta dada en la entrada con un 1 si es que son amigos y un cero en caso contrario

Ejemplo:
Entrada   Salida
0  
 0  
 1  
 1
Límites

0< N < 100,000

0<M < 100,000

por el momento lo que llevo pensado es lo siguiente:
crear un array del tamaño de los amigos donde ese array almacenara vectores.
ahora como en el ejemplo meten un saludo de las personas 1 y 2.
en el vector de la persona 1 meto el 2
en el vector de la persona 2 meto el 1
con esto se que ambos se conocen.
ahora meten un salud de las personas 2 y 3.
hago lo mismo que arriba pero si nos damos cuenta tambien deben conocerse 1 y 3 asi que debo hacer algo mas.
aqui segun yo lo complicado:
          hago un for que recorra los amigos amigos de "a" donde a cada amigo de "a"
          le agrego un amigo de "a" que no tenga (por el lazo misterioso que mencionan        en el el problema)
por ejemplo:
en este caso el amigo a es 2 que tiene de amigos 1 y 3.
recorro el 2 llego al 1 y checo es amigo de 3 ? no, entonces añadelo
ahora llego al tres y checo es amigo de 1 ? no, entonces añadelo
bueno eso es todo lo que llevo ahora el codigo, que aun no acabo mi idea por lo que les mencione arriba:
Código
  1. #include<bits/stdc++.h>
  2. using namespace std;
  3. typedef struct arrays{
  4.    vector<int>amigos;
  5. }persona;
  6. int main(){    
  7.    bool encontrado;
  8.    char opcion;
  9.    int individuos, preguntas, a, b;
  10.    int i, j, k, l;
  11.    cin>>individuos>>preguntas;
  12.    persona ar[individuos + 1];
  13.    for(i = 0; i < preguntas; i++){
  14.        cin>>opcion>>a>>b;
  15.        if(opcion == 'S'){
  16.            ar[a].amigos.push_back(b);
  17.            ar[b].amigos.push_back(a);
  18.            for(j = 1; j < ar[a].amigos.size(); j++)                
  19.                for(k = j + 1; k < ar[a].amigos.size() + 1; k++)
  20.                    for(l = 0; l < ar[j].amigos.size(); l++)
  21.  
  22.  
  23.        }
  24.        else{
  25.  
  26.        }
  27.    }
  28.    return 0;
  29. }
  30.  
si se les ocurre una idea mejor a la mia por favor!! avisenme!!!


Título: Re: Necesito tu ayuda para resolver un problema en C++
Publicado por: AlbertoBSD en 27 Julio 2016, 12:56 pm
Citar
Una empresa de analisis de comportamiento humano
a.k.a Facebook
 :silbar: :silbar:

Citar
PERO SI NOS DAMOS CUENTA TAMBIEN DEBEN CONOCERSE 1 Y 3 ASI QUE DEBO HACER ALGO MAS.

A lo qu yo entendi esto no es asi, a no ser que este mal redactado o mal traducido. Ya que con solo unir un conjunto de elementos con otros tendrias que agregar todos y cada uno de los elementos a todos los elementos del otro conjunto y viceversa.

Lo que entiendo es que una vez que los vas dando de alta y te pregunten por A o B tu  veas si en ese momento se cumple esa relacion "magica" de amistad.

Pero en cualquiera de los casos, Ya sea de la forma en la que tu lo piensas o yo lo estoy pensando. En Ambos se resuelve con un GRAFO.

En tu caso solo es necesario saber si existe una ruta del nodo A al nodo B

y en mi caso si existe y si su profundidad es de al menos 2

Dado que te imponen tiempos y limite de memoria el problema se trata de complejidad de algoritmo...

Se puede resolver usando un Grafo. Se llena un grafo con los saludos y cuando pregunten por X relacion hay que buscar en el grafo si existe un camino del individuo A a B y si es asi evaluar la ruta mas corta si el numero de saltos o nodos entre A y B es menor o igual a 2.

Si esto es asi entonces A y B son amigos.

Tienes que usar el algoritmo de disjktra.

Saludos


Edito acabo de realizar el programa usando una simplicacion de grafos y búsqueda pero tengo una duda.
Citar
Un numero en una linea por cada pregunta dada en la entrada con un 1 si es que son amigos y un cero en caso contrario

Ejemplo:
Entrada   Salida
0  
 0  
 1  
 1
Límites

Es la  salida de tu primer ejemplo?

Ya que no veo como puede estar conectado 2 con 4 o el ultimo caso 5 con 3 (usando solo un conocido en comun)

por cierto el principal problema es la busqueda de la relacion entre los individuos (nodos)
 ya que si el peor de los casos tiene 100,000 entradas ai lo buscas iterarivamente 100000 veces vas a tardar mas de 1 segundo por caso.

Mi recomendacion seria combinar alguna otra forma de busqueda mas rapida por ejemplo arboles binarios.

En lo que llegue a mi trabajo pego el codigo.

Saludos



Edito nuevamente (Estos ejercicios me gustan mucho)

Recomiendo generar una entrada que realmente estrese el procesador

Hice este codigo que genera el maximo de 100,000 inputs al azar

Código
  1. #include<stdio.h>
  2. #include<stdlib.h>
  3. #include<time.h>
  4.  
  5. #define MAX 100000
  6.  
  7. int main() {
  8. register int i = 0;
  9. srand(time(NULL));
  10. printf("%i %i\n",MAX,MAX);
  11. while(i < MAX) {
  12. printf("%c ",(rand()%2) ? 'P':'S');
  13. printf("%i %i\n",1+ rand()%MAX,1+ rand()%MAX);
  14. i++;
  15. }
  16. }

Y con ese entrada, mi codigo encuentra todas las posibilidades en 1.08 segundos.

La solución que use como les comente es un arbol y búsqueda binaria entre nodos individuales.


No pongo el código del programa por si hay algún otro interesado no afectar su programación.

Saludos!


Título: Re: Necesito tu ayuda para resolver un problema en C++
Publicado por: KINGARZA en 27 Julio 2016, 21:20 pm
muchísimas gracias alberto por responder!!
explicare la salida:
lo primero ya lo dije la relación de 1, 2 y 3.
preguntan 2 conoce a 4 ? no, porque ni siquiera se ha mencionado a 4.
luego preguntan por 5 y 3 como 5 solo es amigo de 4 no hay ninguna relacion asi que no son amigos.
ahora se saludan 4 y 5 esto es como el primer caso donde se saludan 1 y 2.
por ultimo se saludan 5 y 1, aqui la magia, todos los amigos de 1 serán amigos de 5, y como vimos 4 es amigo de 5, asi que todos los amigos de 5 seran amigos de 4, entonces por eso queda la salida queda asi:

0
0
1
1

y si nos damos cuenta al final todos se conocen  :o
mira este el link del problema es un juez en linea https://omegaup.com/arena/problem/am#problems

también gracias por el código lo usare una vez que acabe mi programa.
si alguien puede resolverlo por favor comparta su respuesta, yo si lo acabo lo compartiré.
un saludo!!.



oye y respecto a la implementacion:
¿se puede usar un arbol binario de prioridades?
(priority binary tree)



Título: Re: Necesito tu ayuda para resolver un problema en C++
Publicado por: engel lex en 27 Julio 2016, 21:28 pm
Mod: Lee las reglas del foro y sigue las advertencias!

No escribas en mayúsculas (corregido)
los titulos de los temas deben ser descriptivos!
no hagas doble post!

antes de responder a este tema nuevamente corrige el titulo


Título: Re: Necesito tu ayuda para resolver un problema en C++
Publicado por: AlbertoBSD en 27 Julio 2016, 22:06 pm
Pues a mi me parece algo incorrecta la forma de interpretar la lectura ya que ahi hablan de solo u  amigo en comun.
Citar
un dato curioso es que si existen tres invidividuos A, C, B pertenecientes al espacio, y A es amigo de C y C amigo de B, se genera un lazo mistico mediante el cual A y B son amigos,

Y la implementacion esta hablando del amigo del amigo del amigo.

EN FIN...

La implementacion podria ser cualquier arbol binario para optimizar las busquedas aunque el hecho de tener un arbol por individuo usa mucha memoria.

En minuto mas pongo mi implementacion ( La cual solo aborda el primer ejemplo que yo dije donde solo valido a los amigos del primer amigo)

Código
  1. #include<stdio.h>
  2. #include<string.h>
  3. #include<stdlib.h>
  4. #include<stdbool.h>
  5.  
  6. #define MAXLINE 40
  7.  
  8. struct nodo_arbol {
  9. struct nodo_arbol *padre,*derecho,*izquierdo;
  10. int valor;
  11. };
  12.  
  13. struct nodo {
  14. int id;
  15. int *relations;
  16. int total;
  17. struct nodo_arbol *arbol;
  18. };
  19.  
  20. struct nodo **todos = NULL; //Futuro arreglo de todos los nodos existente
  21.  
  22. void add_relation(int A,int B);
  23. bool existe_salto(int A,int B);
  24.  
  25. struct nodo_arbol *crear_nodo_arbol(struct nodo_arbol *padre,int valor);
  26. struct nodo_arbol *buscar_nodo_arbol(struct nodo_arbol *arbol,int valorAbuscar);
  27. struct nodo_arbol *agregar_valor_arbol(struct nodo_arbol *arbol,int valor);
  28.  
  29.  
  30. int main() {
  31. FILE *in = NULL;
  32. char *line = NULL;
  33. char *delim = " \n";
  34. char *token;
  35. char caso;
  36. int N,M,i,A,B;
  37. in = fopen("amistad.in","r");
  38. line = calloc(MAXLINE,1);
  39. fgets(line,MAXLINE,in);
  40. token = strtok(line,delim);
  41. N = strtol(token,NULL,10);
  42. todos = calloc(sizeof(struct nodo*),N); //Reservamos espacio para al menos N apuntadores a los nodos
  43. token = strtok(NULL,delim);
  44. M = strtol(token,NULL,10);
  45. i = 0;
  46. while(i < M) {
  47. memset(line,0,MAXLINE);
  48. fgets(line,MAXLINE,in);
  49. token = strtok(line,delim);
  50. caso = token[0];
  51. token = strtok(NULL,delim);
  52. A = strtol(token,NULL,10);
  53. A--;
  54. token = strtok(NULL,delim);
  55. B = strtol(token,NULL,10);
  56. B--;
  57. switch(caso){
  58. case 'P':
  59. //printf("P %i %i\n",A+1,B+1);
  60. if(todos[A] && todos[B]) { // Ambos nodos son Validos, entonces hay que buscar si existe al menos un camino de a A a B
  61. if(existe_salto(A,B)) {
  62. printf("1\n");
  63. }
  64. else {
  65. printf("0\n");
  66. }
  67. }
  68. else { // Uno de los nodos es NULL entonces no existe camino de A a B
  69. //printf("Un nodo es invalido\n");
  70. printf("0\n");
  71. }
  72. break;
  73. case 'S':
  74. //printf("S %i %i\n",A+1,B+1);
  75. add_relation(A,B);
  76. break;
  77. }
  78. i++;
  79. }
  80. fclose(in);
  81. return 0;
  82. }
  83.  
  84. void add_relation(int A,int B) {
  85. if(todos[A] != NULL) {
  86. //Nodo ya inicializado;
  87. todos[A]->relations = realloc(todos[A]->relations,sizeof(int)*(todos[A]->total+1));
  88. todos[A]->relations[todos[A]->total] = B;
  89. todos[A]->arbol = agregar_valor_arbol(todos[A]->arbol,B);
  90. todos[A]->total++; //incrementamos el numero total de relaciones que tiene este nodo
  91. }
  92. else {
  93. //Nodo no inicializado
  94. todos[A] = calloc(sizeof(struct nodo),1);
  95. todos[A]->id  = A; //Esto es mera formalidad, ya que actualmente el indice del arreglo ya es el mismo "id"
  96. todos[A]->relations = realloc(todos[A]->relations,sizeof(int)*(todos[A]->total+1));
  97. todos[A]->relations[todos[A]->total] = B;
  98. todos[A]->arbol = agregar_valor_arbol(todos[A]->arbol,B);
  99. todos[A]->total++; //incrementamos el numero total de relaciones que tiene este nodo
  100. }
  101. if(todos[B] != NULL) {
  102. //Nodo ya inicializado;
  103. todos[B]->relations = realloc(todos[B]->relations,sizeof(int)*(todos[B]->total+1));
  104. todos[B]->relations[todos[B]->total] = A;
  105. todos[B]->arbol = agregar_valor_arbol(todos[B]->arbol,A);
  106. todos[B]->total++; //incrementamos el numero total de relaciones que tiene este nodo
  107. }
  108. else {
  109. //Nodo no inicializado
  110. todos[B] = calloc(sizeof(struct nodo),1);
  111. todos[B]->id  = B; //Esto es mera formalidad, ya que actualmente el indice del arreglo ya es el mismo "id"
  112. todos[B]->relations = realloc(todos[B]->relations,sizeof(int)*(todos[B]->total+1));
  113. todos[B]->relations[todos[B]->total] = A;
  114. todos[B]->arbol = agregar_valor_arbol(todos[B]->arbol,A);
  115. todos[B]->total++; //incrementamos el numero total de relaciones que tiene este nodo
  116.  
  117. }
  118. }
  119.  
  120. bool existe_salto(int A,int B) {
  121. bool r = false;
  122. struct nodo *nodo_a = NULL,*nodo_b =NULL,*inicio =NULL,*pivote = NULL;
  123. struct nodo_arbol *busqueda = NULL;
  124. register int i,j,buscar;
  125. nodo_a = todos[A];
  126. nodo_b = todos[B];
  127. if(nodo_a->total < nodo_b->total) {
  128. //printf("Menor A %i\n",A+1);
  129. inicio = nodo_a;
  130. buscar = B;
  131. }
  132. else {
  133. //printf("Menor B %i\n",B+1);
  134. inicio = nodo_b;
  135. buscar = A;
  136. }
  137. i = 0;
  138. //printf("Nodos: ");
  139. while(i < inicio->total && !r) {
  140. //printf("%i\t ",inicio->relations[i]+1);
  141. busqueda = buscar_nodo_arbol(inicio->arbol,buscar);
  142. if(busqueda) {
  143. r = true;
  144. }
  145. i++;
  146. }
  147. //printf("\n");
  148. if(!r) {
  149. i = 0;
  150. while(i < inicio->total && !r) {
  151. pivote = todos[inicio->relations[i]];
  152. j = 0;
  153. //printf("Nodos de %i:  ",inicio->relations[i]+1);
  154. while(j < pivote->total && !r) {
  155. busqueda = buscar_nodo_arbol(pivote->arbol,buscar);
  156. //printf("%i\t ",pivote->relations[j]+1);
  157. if(busqueda) {
  158. r = true;
  159. }
  160. j++;
  161. }
  162. //printf("\n");
  163. i++;
  164. }
  165. }
  166. return r;
  167. }
  168.  
  169.  
  170. struct nodo_arbol *crear_nodo_arbol(struct nodo_arbol *padre,int valor) {
  171. struct nodo_arbol *n = calloc(sizeof(struct nodo_arbol),1);
  172. if(n == NULL) {
  173. printf("Error de Memoria\n");
  174. exit(0);
  175. }
  176. n->padre = padre;
  177. n->valor = valor;
  178. return n;
  179. }
  180.  
  181. struct nodo_arbol *agregar_valor_arbol(struct nodo_arbol *arbol,int valor) {
  182. struct nodo_arbol *temp,*pivote;
  183. int derecho = 0;
  184. if(arbol) {
  185. temp =arbol;
  186. while(temp != NULL) {
  187. pivote = temp;
  188. if(valor > temp->valor) {
  189. temp = temp->derecho;
  190. derecho = 1;
  191. }
  192. else {
  193. temp = temp->izquierdo;
  194. derecho = 0;
  195. }
  196. }
  197. temp = crear_nodo_arbol(pivote,valor);
  198. if(derecho) {
  199. pivote->derecho = temp;
  200. }
  201. else {
  202. pivote->izquierdo = temp;
  203. }
  204. return arbol;
  205. }
  206. else {
  207. temp = crear_nodo_arbol(NULL,valor);
  208. return temp;
  209. }
  210. }
  211.  
  212. struct nodo_arbol *buscar_nodo_arbol(struct nodo_arbol *arbol,int valorAbuscar) {
  213. struct nodo_arbol *temp = NULL,*pivote = NULL;
  214. int entrar = 1;
  215. temp =arbol;
  216. while(entrar == 1  && temp != NULL) {
  217. pivote = temp;
  218. if(valorAbuscar == temp->valor){
  219. entrar = 0;
  220. }
  221. else {
  222. if(valorAbuscar > temp->valor) {
  223. temp = temp->derecho;
  224. }
  225. else {
  226. temp = temp->izquierdo;
  227. }
  228. }
  229. }
  230. return temp;
  231. }

Solo habria que extenderla para que revise todos los nodos.

Saludoa


Título: Re: Propuestas para resolver en C++
Publicado por: engel lex en 27 Julio 2016, 23:37 pm
El titulo debe ser Descriptivo, te explico

Citar
Propuestas para resolver problema en C++


Describe tanto el tema como

Citar
Necesito tu ayuda para resolver un problema en C++

Es decir, no lo describe...
Citar
Describir
verbo transitivo
1.
Explicar cómo es una cosa, una persona o un lugar para ofrecer una imagen o una idea completa de ellos.
"en el manual se describen las principales especies animales que habitan en la zona; entonces aquella ciudad me pareció triste así la recuerdo y así la describo e impregnada de singular melancolía"


Título: Re: Propuestas para resolver problema en C++
Publicado por: AlbertoBSD en 27 Julio 2016, 23:47 pm
Titulos sugeridos:

Código:
¿Mejor algoritmo? Problema con aproximaciones de Grafos

Código:
 Optimizar algoritmo para busqueda de elementos

Saludos


Título: Re: Propuestas para resolver problema en C++
Publicado por: KINGARZA en 28 Julio 2016, 01:09 am
Alberto muchas gracias por compartir tu respuesta y por la propuesta.
Mira la verdad no entiendo mucho el tema de los arboles binarios, solo he creado uno (hace 1 semama aprox.)y pues conozco muy pocas cosas, ademas de que usas cosas nuevas para mi como calloc, strtok , strtol, etc..
Pero me esforzare mucho en tratar de entenderlo.
En cuanto a mi, les comparto mi respuesta ya la envie a la pagina y me da estos resultados:
Status: Tiempo Limite Excedido.
Porcentaje: 90%.
Memoria: 48.98 MB.
Tiempo: >2.78 s.
Como ven es buena respuesta pues me da el 90%.
Y ahora explicare que fue lo que hice:
Después de buscar en internet me encontré con el set que es un contenedor asociativo que tiene la característica de no guardar valores repetidos y los guarda en orden.
entonces aqui reemplazaba los vectores por los sets.
ahora, lo mas complicado es donde se saludan lo explique anteriormente, ahora lo hare mejor:
se saluda 1 y 2.
en el set de 1 pongo el 2.
en el set de 2 pongo el 1.
ahora recorro el set de 1 y a los amigos de 1 les agregare los amigos de 1, lo mismo hago con el 2, pero como ambos sets tienen un solo elemento que son 1 y 2 respectivamente no pasa nada.
se saluda 2 y 3.
en el set de 2 pongo el 3.
en el set de 3 pongo el 2.
ahora recorro el set de 2 y a sus amigos les añado los amigos de 2.
lo mismo hago con el 3.
entonces hasta ahora los sets quedan asi:
persona:                 conocidos:
   1                              2,3
   2                              1,3
   3                              1,2
preguntan 2 conoce a 4 ?
checo, si cualquier set esta vacio (A o B)entonces quiere decir que no, pues no a saludado a nadie, sino recorro el set de la persona A y busco si esta la persona B.
en este caso es NO.
se saluda 4 y 5.
en el set de 4 pongo el 5.
en el set de 5 pongo el 4.
ahora recorro el set de 4 y a los amigos de 4 les agregare los amigos de 4, lo mismo hago con el 5, pero como ambos sets tienen un solo elemento que son 4 y 5 respectivamente no pasa nada.
entonces hasta ahora los sets quedan asi:
persona:                 conocidos:
   1                              2,3
   2                              1,3
   3                              1,2
   4                              5
   5                              4  
ahora preguntan 5 conoce a 3?
checo, si cualquier set esta vacio (A o B) entonces quiere decir que no, pues no a saludado a nadie, sino recorro el set de la persona A y busco si esta la persona B.
en este caso es NO.
Por ultimo se saluda 5 con 1.
en el set de 5 pongo el 1.
en el set de 1 pongo el 5.
ahora recorro el set de 5 y a todos sus amigos les añado los amigos que no tengan de 5, lo mismo hago con el 1 y si nos damos cuenta ya todos son amigos, por ende las siguientes preguntas son SI.
Aqui les dejo el codigo:
Código
  1. #include<bits/stdc++.h>
  2. using namespace std;
  3.                            /*DECLARO TODO LO QUE USARE DE SET Y EL VECTOR QUE GUARDARA LAS RESPUESTAS*/
  4. typedef struct arrays{
  5.    set<int>amigos;
  6. }ar;
  7.     set<int>::iterator j;
  8.     set<int>::iterator k;
  9.     vector<string>respuestas;
  10.  
  11. int main(){
  12.    cin.tie(0);
  13.    ios_base::sync_with_stdio(0);
  14.    bool encontrado;
  15.    char opcion;
  16.    int personas, comandos, a, b;
  17.    int i, l, z;
  18.    cin>>personas>>comandos;
  19.  
  20.    ar persona[personas + 1]; /*CREAMOS UN ARRAY DE SETS DE TAMAÑO PERSONAS*/
  21.  
  22.    for(i = 0; i < comandos; i++){
  23.        cin>>opcion>>a>>b;
  24.        if(opcion == 'S'){
  25.            persona[a].amigos.insert(b);
  26.            persona[b].amigos.insert(a);
  27.            for(j = persona[a].amigos.begin(); j != persona[a].amigos.end(); j++){ /* PERSONA A*/
  28.                for(k = persona[a].amigos.begin(); k != persona[a].amigos.end(); k++){
  29.                    persona[*j].amigos.insert(*k);
  30.                }
  31.            }
  32.            for(j = persona[b].amigos.begin(); j != persona[b].amigos.end(); j++){ /*PERSONA B*/
  33.                for(k = persona[b].amigos.begin(); k != persona[b].amigos.end(); k++){
  34.                    persona[*j].amigos.insert(*k);
  35.                }
  36.            }
  37.        }
  38.        else{
  39.            if(persona[a].amigos.empty() || persona[b].amigos.empty())
  40.                respuestas.push_back("0\n");
  41.            else{
  42.                encontrado = false;
  43.                for(j = persona[a].amigos.begin(); j != persona[a].amigos.end(); j++){/*BUSCAMOS SI EN LOS AMIGOS DE A ESTA B*/
  44.                    if(*j == b){
  45.                        encontrado = true;
  46.                        break;
  47.                    }
  48.                }
  49.                if(encontrado)
  50.                    respuestas.push_back("1\n");
  51.                else
  52.                    respuestas.push_back("0\n");
  53.            }
  54.        }
  55.    }
  56.    for(i = 0; i < respuestas.size(); i++)
  57.        cout<<respuestas[i];
  58.    return 0;
  59. }
Creo que si optimizamos la búsqueda de la persona B en A y al agregar amigos podría dar el 100%
Encontre en internet algo llamado set_union y merge para eso de añadir los amigos pero eso de buscar los amigos pensaba en una búsqueda binario aunque según yo que no es posible.


Título: Re: ¿Mejor algoritmo? Problema con aproximaciones de Grafos
Publicado por: AlbertoBSD en 28 Julio 2016, 01:40 am
Hola.

Citar
pensaba en una búsqueda binario aunque según yo que no es posible.

Los arboles binarios por su diseño implementan una busqueda binaria


Si lo quieres manejar manualmente en un array tendrias que ordenarlos para posteriormente hacer una búsqueda binaria.

Calcule la memoria que usaria mi codigo y seria cerca de 2 MB en el peor de los casos (100000) inputs.

hay veces que me complico programando en C ya que me gusta saber que hace exactamente el codigo. Lo que tu haces con un simple cin>>  yo lo hago como con 10 lineas de codigo y au que son muchas lineas siento que se ejecuta igual de rapido que un cin o incluso mas rapido aun...

Busca como implementar una busqueda binaria y el algoritmo de disjktra es lo mas rapido que vas a encontrar y terminarias usando menos memoria.

Voy a adaptar mi codigo a C++ para que veas como funciona.

Mientras te dejo unos videos que hice de arboles binarios

BBsgYwXGdI8

hlWvK1EU-oA

Saludos


Título: Re: ¿Mejor algoritmo? Problema con aproximaciones de Grafos
Publicado por: KINGARZA en 28 Julio 2016, 06:40 am
Alberto un pregunta en cuanto a tu video, como te comente ya habia hecho un arbol binario, pero yo en la estructura del nodo solo habia utilizado el dato y los dos punteros izquierdo y derecho, mi pregunta es ¿Para que sirve el nodo padre?
Bueno y otra duda, en tu arbol binario del problema quien es la raiz o como funciona eso de ir añadiendo nodos (disculpa mi ignorancia)?
Mira este es mi codigo:
Código
  1. #include <bits/stdc++.h>
  2. using namespace std;
  3.  
  4. struct nodoArbol {
  5. struct nodoArbol *ptrIzq;
  6. int dato;
  7. struct nodoArbol *prtDer;
  8. };
  9.  
  10. typedef struct nodoArbol NodoArbol;
  11. typedef NodoArbol *ptrNodoArbol;
  12.  
  13. void insertaNodo( ptrNodoArbol *ptrArbol, int valor ){
  14.  
  15.    if (*ptrArbol == NULL) { /*ARBOL VACIO*/
  16.        *ptrArbol = (NodoArbol*)malloc(sizeof(NodoArbol));
  17.        (*ptrArbol)->dato = valor;
  18.        (*ptrArbol)->ptrIzq = NULL;
  19.        (*ptrArbol)->prtDer = NULL;
  20.    }
  21.  
  22.    else {
  23.        /* el dato a insertar es menor que el dato en el nodo actual */
  24.        if (valor < (*ptrArbol)->dato) {
  25.            insertaNodo(&((*ptrArbol)->ptrIzq), valor);
  26.        }
  27.        else if (valor > (*ptrArbol)->dato) {
  28.            insertaNodo(&((*ptrArbol)->prtDer), valor);
  29.        }
  30.    }
  31. }
  32.  
  33. void inOrden(ptrNodoArbol ptrArbol){
  34.    if (ptrArbol != NULL) {
  35.        inOrden(ptrArbol->ptrIzq);
  36.        cout<<ptrArbol -> dato<<" ";
  37.        inOrden(ptrArbol->prtDer);
  38.    }
  39. }
  40.  
  41. void preOrden(ptrNodoArbol ptrArbol){
  42.    if (ptrArbol != NULL){
  43.        cout<<ptrArbol -> dato<<" ";
  44.        preOrden(ptrArbol->ptrIzq);
  45.        preOrden(ptrArbol->prtDer);
  46.    }
  47. }
  48.  
  49. void postOrden(ptrNodoArbol ptrArbol) {
  50.    if (ptrArbol != NULL){
  51.        postOrden(ptrArbol->ptrIzq);
  52.        postOrden(ptrArbol->prtDer);
  53.        cout<<ptrArbol -> dato<<" ";
  54.    }
  55. }
  56.  
  57. int main(){
  58.  
  59.    ptrNodoArbol ptrRaiz = NULL;
  60.    int limite,elemento;
  61.    cout<<"INTRODUCE CUANTOS ELEMENTOS TENDRA EL ARBOL: ";
  62.    cin>>limite;
  63.  
  64.    for (int i = 1; i <= limite; i++) {
  65.        cout<<"INGRESE ELEMENTO: ";
  66.        cin>>elemento;
  67.        insertaNodo(&ptrRaiz, elemento);
  68.    }
  69.  
  70.    cout<<"\nEL RECORRIDO EN PREORDEN ES:\n";
  71.    preOrden(ptrRaiz);
  72.  
  73.    cout<<"\nEL RECORRIDO EN INORDEN ES:\n";
  74.    inOrden(ptrRaiz);
  75.  
  76.    cout<<"\nEL RECORRIDO EN POSTORDEN ES:\n";
  77.    postOrden(ptrRaiz);
  78.  
  79.    return 0;
  80. }
Gracias por tu ayuda.


Título: Re: ¿Mejor algoritmo? Problema con aproximaciones de Grafos
Publicado por: AlbertoBSD en 28 Julio 2016, 15:41 pm
La raiz es el primer nodo que se inserta..

Su padre es null.

Tus funciones de inOrden o preorden son recursivas y no necesitan saber quien es el padre, aun asi gastan mas memoria. En funciones iterativas es mecesario saber quien es el podre y gastan menos memoria.

En ocasiones es necesario separar subarboles o eliminar arboles completos, y tambien facilita mucho tener una referencia al padre.

Basicamente es una facilidad tener esa referencia en fumciones iterarivas.

Como reto deberias de hacer tu funcion inOrden y preOrden de forma iterativa, Esto es sin llamar a las funciones dichas desde si mismas.

Saludos!



Título: Re: ¿Mejor algoritmo? Problema con aproximaciones de Grafos
Publicado por: do-while en 29 Julio 2016, 09:58 am
Interesante ejercicio.

Se trata de crear particiones sobre el conjunto de personas (tenemos una relación de equivalencia en un conjunto->la equivalencia crea una partición del conjunto (un conjunto de subconjuntos disjuntos)).

Se me ocurre que se puede tener un vector (mejor árbol, que así no hay que estar desplazando valores para mantener el orden después de una inserción) con pares del tipo numero_persona-clase. Así la cuestión de decidir si dos personas son amigos se reduce a realizar la búsqueda de las dos personas y ver si pertenecen a la misma clase, y la inserción se podría hacer en un vector (sabemos que el máximo numero de parejas es 100.000 / 2) en el que cada componente sea un vector de punteros a los nodos del árbol que formen parte de la misma clase. Así, a través de los punteros de la tabla, si hubiese que fusionar dos clases sería muy fácil corregir directamente en cada nodo del árbol la clase a la que pertenece el par persona-clase. La tabla mantiene una lista de todas las personas relacionadas entre sí y soluciona el problema de buscar en el árbol todas las personas que pertenecen a la misma clase.

A ver que sale de esta idea.

¡Saludos!


Con el planteamiento anterior, cambiando la idea de un vector de vectores por la de un vector de árboles, en mi ordenador, el tiempo de ejecución en el caso de la entrada de mayor dimensión se pasa del segundo por poco. Entre 1'2 y 1'3 segundos.

Alberto, te mando el código por MP, como los planteamientos son distintos me gustaría ver tu código.

¡Saludos!


Título: Re: ¿Mejor algoritmo? Problema con aproximaciones de Grafos
Publicado por: AlbertoBSD en 29 Julio 2016, 14:52 pm
 ;-) ;-)  ;-)

Excelente aproximacion. Aun no veo tu codigo pero.... la idea es genial y de hecho es mas rápido que un Grafo con Disjktra...

Fucionar arboles seria mas rapido y las consultas prácticamente ya están hechas al tener un valor que nos indiqué a que conjunto o "arbol" pertenece un nodo facilmente se puede saber si existe ese lazo o no.

En lo que llegue al trabajo te pado mi codigo.

Saludos


Título: Re: ¿Mejor algoritmo? Problema con aproximaciones de Grafos
Publicado por: do-while en 29 Julio 2016, 21:38 pm
Bueno... hoy estoy muy tonto. Pensaba que en los códigos anteriores discutíais sobre opciones para resolver el problema. Veo que ya hay alguna solución, así que dejo la mía también. main está al final y justo antes están las funciones problema_interactivo y problema_aleatorio. La primera solicita los datos desde el teclado, la segunda genera 100.000 casos aleatorios y los procesa.
Código
  1. #include <stdio.h>
  2. #include <stdlib.h>
  3. #include <string.h>
  4. #include <time.h>
  5.  
  6. #define DIM 100000
  7.  
  8. struct Persona
  9. {
  10. int valor;
  11. int clase;
  12. };
  13. typedef struct Persona Persona;
  14.  
  15. struct NodoArbolPersona
  16. {
  17. Persona *persona;
  18.  
  19. struct NodoArbolPersona *menores, *mayores;
  20. };
  21. typedef struct NodoArbolPersona NodoArbolPersona;
  22.  
  23. void insertar(NodoArbolPersona **arbol, Persona *persona)
  24. {
  25. if(!(*arbol))
  26. {
  27. (*arbol) = malloc(sizeof(NodoArbolPersona));
  28. (*arbol)->persona = persona;
  29. (*arbol)->menores = NULL;
  30. (*arbol)->mayores = NULL;
  31.  
  32. return;
  33. }
  34.  
  35. if(persona->valor < (*arbol)->persona->valor)
  36. insertar(&((*arbol)->menores), persona);
  37. else
  38. insertar(&((*arbol)->mayores), persona);
  39. }
  40.  
  41. Persona* buscar(NodoArbolPersona *arbol, int valor)
  42. {
  43. if(!arbol)
  44. return NULL;
  45.  
  46. if(arbol->persona->valor == valor)
  47. return arbol->persona;
  48.  
  49. if(valor < arbol->persona->valor)
  50. return buscar(arbol->menores, valor);
  51.  
  52. return buscar(arbol->mayores,valor);
  53. }
  54.  
  55. void cambiar_clase(NodoArbolPersona *amigos, int nueva_clase)
  56. {
  57. if(!amigos)
  58. return;
  59.  
  60. amigos->persona->clase = nueva_clase;
  61.  
  62. cambiar_clase(amigos->menores, nueva_clase);
  63. cambiar_clase(amigos->mayores, nueva_clase);
  64. }
  65.  
  66. void fusionar_arboles(NodoArbolPersona **destino, NodoArbolPersona *origen)
  67. {
  68. if(!(*destino))
  69. *destino = origen;
  70.  
  71. if((*destino)->persona->valor == origen->persona->valor)
  72. return;
  73.  
  74. if(origen->persona->valor < (*destino)->persona->valor)
  75. fusionar_arboles(&((*destino)->menores),origen);
  76. else
  77. fusionar_arboles(&((*destino)->mayores),origen);
  78.  
  79. }
  80.  
  81. void insertar_amigos(NodoArbolPersona *amigos[DIM/2], NodoArbolPersona **personas, int a, int b)
  82. {
  83. Persona *persona1,*persona2, *aux;
  84. int i,clase_aux;
  85.  
  86. if((persona1 = buscar(*personas,a)))
  87. {
  88. if((persona2 = buscar(*personas,b))) //ambas personas existen
  89. {
  90. if(persona1->clase != persona2->clase)
  91. {
  92. //pertenecen a distintas clases y hay que fusionarlas
  93. if(persona1->clase > persona2->clase)
  94. {
  95. aux = persona2;
  96. persona2 = persona1;
  97. persona1 = aux;
  98. }
  99.  
  100. clase_aux = persona2->clase;
  101. cambiar_clase(amigos[persona2->clase],persona1->clase); //cambiamos toda la clase b para que apunte a a.
  102. fusionar_arboles(&(amigos[persona1->clase]),amigos[clase_aux]); //añadimos toda el arbol b a a.
  103. amigos[clase_aux] = NULL;
  104. }
  105. }
  106. else //existe p1, pero no p2
  107. {
  108. persona2 = malloc(sizeof(Persona));
  109.  
  110. persona2->valor = b;
  111. persona2->clase = persona1->clase;
  112.  
  113. insertar(personas, persona2);
  114. insertar(&(amigos[persona1->clase]), persona2);
  115. }
  116. }
  117. else //persona1 no existe
  118. {
  119. if((persona2 = buscar(*personas,b)))
  120. {
  121. //existe p2 pero no p1
  122. persona1 = malloc(sizeof(Persona));
  123.  
  124. persona1->valor = a;
  125. persona1->clase = persona2->clase;
  126.  
  127. insertar(personas, persona1);
  128. insertar(&(amigos[persona2->clase]), persona1);
  129. }
  130. else //no existen ninguna de las dos personas
  131. {
  132. //buscamos la primera clase que este vacia
  133. for(i = 0 ; amigos[i] ; i++);
  134.  
  135. //creamos las personas:
  136. persona1 = malloc(sizeof(Persona));
  137. persona2 = malloc(sizeof(Persona));
  138.  
  139. persona1->valor = a;
  140. persona2->valor = b;
  141. persona1->clase = persona2->clase = i;
  142.  
  143. insertar(personas,persona1);
  144. insertar(personas,persona2);
  145.  
  146. insertar(&(amigos[i]),persona1);
  147. insertar(&(amigos[i]),persona2);
  148.  
  149. }
  150. }
  151.  
  152. return;
  153. }
  154.  
  155. //tenemos dos funciones para liberar la memoria de los arboles
  156. //la unica diferencia es que la primera libera el dato "persona"
  157. //y la segunda no.
  158. void destruir_personas(NodoArbolPersona **personas)
  159. {
  160. if(!(*personas))
  161. return;
  162.  
  163. destruir_personas(&((*personas)->menores));
  164. destruir_personas(&((*personas)->mayores));
  165.  
  166. free((*personas)->persona);
  167. free(*personas);
  168.  
  169. *personas = NULL;
  170. }
  171.  
  172. void destruir_clase(NodoArbolPersona **amigos)
  173. {
  174. if(!(*amigos))
  175. return;
  176.  
  177. destruir_personas(&((*amigos)->menores));
  178. destruir_personas(&((*amigos)->mayores));
  179.  
  180. free(*amigos);
  181.  
  182. *amigos = NULL;
  183. }
  184.  
  185. void problema_interactivo()
  186. {
  187. //cada componente del vector es un arbol que relaciona los amigos que forman una "clase"
  188. NodoArbolPersona *clases[DIM / 2], *personas = NULL; //personas: arbol de elementos valor-clase
  189. Persona *persona1, *persona2;
  190. int num_personas, num_casos, amigo1, amigo2;
  191. char operador;
  192.  
  193. for(num_personas = 0 ; num_personas < DIM / 2 ; num_personas++)
  194. clases[num_personas] = NULL;
  195.  
  196. scanf("%d", &num_personas);
  197. scanf("%d", &num_casos);
  198. while(getchar() != '\n');
  199.  
  200. while(num_casos--)
  201. {
  202. scanf("%c%d%d", &operador, &amigo1, &amigo2);
  203. while(getchar() != '\n');
  204.  
  205. switch(operador)
  206. {
  207. case 'S':
  208. insertar_amigos(clases, &personas,amigo1, amigo2);
  209. break;
  210.  
  211. case 'P':
  212. if((persona1 = buscar(personas,amigo1)) && (persona2 = buscar(personas,amigo2)))
  213. {
  214. if(persona1->clase == persona2->clase)
  215. printf("1\n");
  216. else
  217. printf("0\n");
  218. }
  219. else
  220. printf("0\n");
  221. }
  222. }
  223.  
  224. destruir_personas(&personas);
  225.  
  226. for(num_personas = 0 ; num_personas < DIM / 2 ; num_personas++)
  227. destruir_clase(&(clases[num_personas]));
  228. }
  229.  
  230. void problema_aleatorio()
  231. {
  232. //cada componente del vector es un arbol que relaciona los amigos que forman una "clase"
  233. NodoArbolPersona *clases[DIM / 2], *personas = NULL; //personas: arbol de elementos valor-clase
  234. Persona *persona1, *persona2;
  235. int num_personas, num_casos = DIM, amigo1, amigo2;
  236. char operador;
  237. char entrada[20];
  238.  
  239. srand(time(NULL));
  240.  
  241. for(num_personas = 0 ; num_personas < DIM / 2 ; num_personas++)
  242. clases[num_personas] = NULL;
  243.  
  244. while(num_casos--)
  245. {
  246. //vamos a forzar a que, aproximadamente, el 60% de los casos sean saludos
  247. sprintf(entrada,"%c %d %d",rand() % 10 < 6 ? 'S' : 'P', rand() % (DIM + 1), rand() % (DIM + 1));
  248. sscanf(entrada,"%c%d%d", &operador, &amigo1, &amigo2);
  249.  
  250. switch(operador)
  251. {
  252. case 'S':
  253. insertar_amigos(clases, &personas,amigo1, amigo2);
  254. break;
  255.  
  256. case 'P':
  257. if((persona1 = buscar(personas,amigo1)) && (persona2 = buscar(personas,amigo2)))
  258. {
  259. if(persona1->clase == persona2->clase)
  260. printf("1\n");
  261. else
  262. printf("0\n");
  263. }
  264. else
  265. printf("0\n");
  266. }
  267. }
  268.  
  269. destruir_personas(&personas);
  270.  
  271. for(num_personas = 0 ; num_personas < DIM / 2 ; num_personas++)
  272. destruir_clase(&(clases[num_personas]));
  273. }
  274.  
  275. int main(int argc, char *argv[])
  276. {
  277. //problema_interactivo();
  278. problema_aleatorio();
  279.  
  280. return 0;
  281. }
  282.  


Título: Re: ¿Mejor algoritmo? Problema con aproximaciones de Grafos
Publicado por: AlbertoBSD en 30 Julio 2016, 18:04 pm
Hola!

Dejo aqui mis 2 implementaciones

La primera con Un Grafo y Disjktra simplificado

Y la segunda como lo sugirio do-while con un arbol y una referencia a que arbol/clase/conjunto pertenece cada nodo (Esta última es la mas rapida)

Código
  1. #include<stdio.h>
  2. #include<string.h>
  3. #include<stdlib.h>
  4. #include<stdbool.h>
  5. #include<time.h>
  6.  
  7.  
  8. #define MAXLINE 40
  9.  
  10. struct nodo_arbol {
  11. struct nodo_arbol *padre,*derecho,*izquierdo; // 12 u 24 bytes
  12. int valor; // 4 bytes
  13. }; //Total 16 u 28 bytes por Nodo
  14. //peor Caso 28 bytes * 100,000 nodos = ~2.8 MB
  15.  
  16. struct nodo {
  17. int id; //4 bytes
  18. int *relations; //4 ú 8 bytes
  19. int total; //4 bytes
  20. struct nodo_arbol *arbol; //4 ú 8 bytes
  21. int offset;
  22. int visitado;
  23. }; //Total 16 u 24 bytes por Nodo
  24. ///peor Caso 24 bytes * 100,000 nodos = ~2.40 MB
  25.  
  26. struct nodo **todos = NULL; //Futuro arreglo de todos los nodos existente
  27. //4 y 8 bytes
  28. //Peor caso 8 bytes * 100,000   = ~800 KB
  29.  
  30. void add_relation(int A,int B);
  31. bool existe_salto(int A,int B);
  32.  
  33. struct nodo_arbol *crear_nodo_arbol(struct nodo_arbol *padre,int valor);
  34. struct nodo_arbol *buscar_nodo_arbol(struct nodo_arbol *arbol,int valorAbuscar);
  35. struct nodo_arbol *agregar_valor_arbol(struct nodo_arbol *arbol,int valor);
  36.  
  37.  
  38. int main() {
  39. FILE *in = NULL;
  40. char *line = NULL;
  41. char *delim = " \n";
  42. char *token;
  43. char caso;
  44. int N,M,i,A,B;
  45. in = fopen("amistad.in","r"); //Archivo ¬¬
  46. srand(time(NULL)); // Para los nodos visitados...
  47. line = calloc(MAXLINE,1);
  48. //Leemos la primera linea
  49. fgets(line,MAXLINE,in);
  50. token = strtok(line,delim);
  51. N = strtol(token,NULL,10);
  52. todos = calloc(sizeof(struct nodo*),N); //Reservamos espacio para al menos N apuntadores a los nodos
  53. token = strtok(NULL,delim);
  54. M = strtol(token,NULL,10);
  55. //Leemos las siguientes M lineas y evaluamos
  56. i = 0;
  57. while(i < M) {
  58. memset(line,0,MAXLINE);
  59. //Leemos la M,esima linea
  60. fgets(line,MAXLINE,in);
  61. token = strtok(line,delim);
  62. caso = token[0];
  63. token = strtok(NULL,delim);
  64. A = strtol(token,NULL,10);
  65. A--;
  66. token = strtok(NULL,delim);
  67. B = strtol(token,NULL,10);
  68. B--;
  69. //Evaluamos
  70. switch(caso){
  71. case 'P':
  72. //printf("P %i %i\n",A+1,B+1);
  73. if(todos[A] && todos[B]) { // Ambos nodos son Validos, entonces hay que buscar si existe al menos un camino de a A a B
  74. if(existe_salto(A,B)) {
  75. printf("1\n");
  76. }
  77. else {
  78. printf("0\n");
  79. }
  80. }
  81. else { // Uno de los nodos es NULL entonces no existe camino de A a B
  82. //printf("Un nodo es invalido\n");
  83. printf("0\n");
  84. }
  85. break;
  86. case 'S':
  87. //printf("S %i %i\n",A+1,B+1);
  88. add_relation(A,B);
  89. break;
  90. }
  91. i++;
  92. }
  93. fclose(in);
  94. return 0;
  95. }
  96.  
  97. void add_relation(int A,int B) {
  98. if(todos[A] != NULL) {
  99. //Nodo ya inicializado;
  100. todos[A]->relations = realloc(todos[A]->relations,sizeof(int)*(todos[A]->total+1));
  101. todos[A]->relations[todos[A]->total] = B;
  102. todos[A]->arbol = agregar_valor_arbol(todos[A]->arbol,B);
  103. todos[A]->total++; //incrementamos el numero total de relaciones que tiene este nodo
  104. }
  105. else {
  106. //Nodo no inicializado
  107. todos[A] = calloc(sizeof(struct nodo),1);
  108. todos[A]->id  = A; //Esto es mera formalidad, ya que actualmente el indice del arreglo ya es el mismo "id"
  109. todos[A]->relations = realloc(todos[A]->relations,sizeof(int)*(todos[A]->total+1));
  110. todos[A]->relations[todos[A]->total] = B;
  111. todos[A]->arbol = agregar_valor_arbol(todos[A]->arbol,B);
  112. todos[A]->total++; //incrementamos el numero total de relaciones que tiene este nodo
  113. todos[A]->visitado = 0;
  114. todos[A]->offset = 0;
  115. }
  116. if(todos[B] != NULL) {
  117. //Nodo ya inicializado;
  118. todos[B]->relations = realloc(todos[B]->relations,sizeof(int)*(todos[B]->total+1));
  119. todos[B]->relations[todos[B]->total] = A;
  120. todos[B]->arbol = agregar_valor_arbol(todos[B]->arbol,A);
  121. todos[B]->total++; //incrementamos el numero total de relaciones que tiene este nodo
  122.  
  123. }
  124. else {
  125. //Nodo no inicializado
  126. todos[B] = calloc(sizeof(struct nodo),1);
  127. todos[B]->id  = B; //Esto es mera formalidad, ya que actualmente el indice del arreglo ya es el mismo "id"
  128. todos[B]->relations = realloc(todos[B]->relations,sizeof(int)*(todos[B]->total+1));
  129. todos[B]->relations[todos[B]->total] = A;
  130. todos[B]->arbol = agregar_valor_arbol(todos[B]->arbol,A);
  131. todos[B]->total++; //incrementamos el numero total de relaciones que tiene este nodo
  132. todos[B]->visitado = 0;
  133. todos[B]->offset = 0;
  134. }
  135. }
  136.  
  137. //A.k.a diskjtra simplificado a aristas de valor 1 y solo valida que exista la union
  138. bool existe_salto(int A,int B) {
  139. bool r = false,outs = false;
  140. struct nodo *nodo_a = NULL,*nodo_b =NULL,*inicio =NULL,*pivote = NULL;
  141. struct nodo_arbol *busqueda = NULL;
  142. struct nodo **pendientes = NULL;
  143. register int i,j,buscar,total = 0;
  144. int visitado;
  145. visitado = rand();
  146. nodo_a = todos[A];
  147. nodo_b = todos[B];
  148. if(nodo_a->total < nodo_b->total) {
  149. inicio = nodo_a;
  150. buscar = B;
  151. //printf("Menor A %i\n",inicio->id+1);
  152. }
  153. else {
  154. inicio = nodo_b;
  155. buscar = A;
  156. //printf("Menor B %i\n",inicio->id+1);
  157. }
  158. //printf("Nodos: ");
  159. i = 0;
  160. pendientes = realloc(pendientes,sizeof(struct nodo*)*(total+1));
  161. pendientes[total] = inicio;
  162. total++;
  163. while(!r && i < total) {
  164. pivote = pendientes[i];
  165. pivote->visitado = visitado;
  166. //printf("Visitando %i\n",pivote->id+1);
  167. busqueda = buscar_nodo_arbol(pivote->arbol,buscar);
  168. if(!busqueda) {
  169. //printf("El nodo %i no tiene el nodo buscado %i\n",pivote->id+1,buscar+1);
  170. j = 0;
  171. while(j < pivote->total ) {
  172. if(todos[pivote->relations[j]]->visitado != visitado) {
  173. //printf("Anexando el nodo %i para su posterior visita\n",todos[pivote->relations[j]]->id+1);
  174. pendientes = realloc(pendientes,sizeof(struct nodo*)*(total+1));
  175. pendientes[total] = todos[pivote->relations[j]];
  176. total++;
  177. }
  178. j++;
  179. }
  180. }
  181. else {
  182. //printf("El nodo %i SI tiene el nodo buscado %i\n",pivote->id+1,buscar+1);
  183. r = true;
  184. }
  185. i++;
  186. }
  187. free(pendientes);
  188. return r;
  189. }
  190.  
  191. //Funciones de Arbol (Solo como almacenamiento y busqueda rapida)
  192.  
  193. struct nodo_arbol *crear_nodo_arbol(struct nodo_arbol *padre,int valor) {
  194. struct nodo_arbol *n = calloc(sizeof(struct nodo_arbol),1);
  195. if(n == NULL) {
  196. printf("Error de Memoria\n");
  197. exit(0);
  198. }
  199. n->padre = padre;
  200. n->valor = valor;
  201. return n;
  202. }
  203.  
  204. struct nodo_arbol *agregar_valor_arbol(struct nodo_arbol *arbol,int valor) {
  205. struct nodo_arbol *temp,*pivote;
  206. int derecho = 0;
  207. if(arbol) {
  208. temp =arbol;
  209. while(temp != NULL) {
  210. pivote = temp;
  211. if(valor > temp->valor) {
  212. temp = temp->derecho;
  213. derecho = 1;
  214. }
  215. else {
  216. temp = temp->izquierdo;
  217. derecho = 0;
  218. }
  219. }
  220. temp = crear_nodo_arbol(pivote,valor);
  221. if(derecho) {
  222. pivote->derecho = temp;
  223. }
  224. else {
  225. pivote->izquierdo = temp;
  226. }
  227. return arbol;
  228. }
  229. else {
  230. temp = crear_nodo_arbol(NULL,valor);
  231. return temp;
  232. }
  233. }
  234.  
  235. struct nodo_arbol *buscar_nodo_arbol(struct nodo_arbol *arbol,int valorAbuscar) {
  236. struct nodo_arbol *temp = NULL,*pivote = NULL;
  237. int entrar = 1;
  238. temp =arbol;
  239. while(entrar == 1  && temp != NULL) {
  240. pivote = temp;
  241. if(valorAbuscar == temp->valor){
  242. entrar = 0;
  243. }
  244. else {
  245. if(valorAbuscar > temp->valor) {
  246. temp = temp->derecho;
  247. }
  248. else {
  249. temp = temp->izquierdo;
  250. }
  251. }
  252. }
  253. return temp;
  254. }


Código
  1. #include<stdio.h>
  2. #include<string.h>
  3. #include<stdlib.h>
  4. #include<stdbool.h>
  5. #include<time.h>
  6.  
  7. #define MAXLINE 40
  8.  
  9. struct nodo_arbol {
  10. struct nodo_arbol *padre,*derecho,*izquierdo;
  11. struct nodo *valor;
  12. };
  13.  
  14. struct arbol {
  15. struct nodo_arbol *raiz;
  16. struct nodo_arbol **nodos;
  17. int total;
  18. };
  19.  
  20. struct nodo {
  21. int id;
  22. struct arbol *arbol;
  23. };
  24.  
  25. struct nodo **todos = NULL;
  26.  
  27. void add_relation(int A,int B);
  28. bool existe_salto(int A,int B);
  29. struct arbol *funciona_arbol(struct arbol *A,struct arbol *B);
  30.  
  31. struct nodo_arbol *crear_nodo_arbol(struct nodo_arbol *padre,struct nodo *valor);
  32. struct arbol *agregar_valor_arbol(struct arbol *arbol,struct nodo *valor);
  33.  
  34. int main() {
  35. FILE *in = NULL;
  36. char *line = NULL;
  37. char *delim = " \n";
  38. char *token;
  39. char caso;
  40. int N,M,i,A,B;
  41. in = fopen("amistad.in","r"); //Archivo ¬¬
  42. srand(time(NULL)); // Para los nodos visitados...
  43. line = calloc(MAXLINE,1);
  44. //Leemos la primera linea
  45. fgets(line,MAXLINE,in);
  46. token = strtok(line,delim);
  47. N = strtol(token,NULL,10);
  48. todos = calloc(sizeof(struct nodo*),N); //Reservamos espacio para al menos N apuntadores a los nodos
  49. token = strtok(NULL,delim);
  50. M = strtol(token,NULL,10);
  51. //Leemos las siguientes M lineas y evaluamos
  52. i = 0;
  53. while(i < M) {
  54. memset(line,0,MAXLINE);
  55. //Leemos la M,esima linea
  56. fgets(line,MAXLINE,in);
  57. token = strtok(line,delim);
  58. caso = token[0];
  59. token = strtok(NULL,delim);
  60. A = strtol(token,NULL,10);
  61. A--;
  62. token = strtok(NULL,delim);
  63. B = strtol(token,NULL,10);
  64. B--;
  65. //Evaluamos
  66. switch(caso){
  67. case 'P':
  68. //printf("P %i %i\n",A+1,B+1);
  69. if(todos[A] && todos[B]) { // Ambos nodos son Validos, entonces hay que buscar si existe al menos un camino de a A a B
  70. if(existe_salto(A,B)) {
  71. printf("1\n");
  72. }
  73. else {
  74. printf("0\n");
  75. }
  76. }
  77. else { // Uno de los nodos es NULL entonces no existe camino de A a B
  78. //printf("Un nodo es invalido\n");
  79. printf("0\n");
  80. }
  81. break;
  82. case 'S':
  83. //printf("S %i %i\n",A+1,B+1);
  84. add_relation(A,B);
  85. break;
  86. }
  87. i++;
  88. }
  89. fclose(in);
  90. return 0;
  91. }
  92.  
  93. void add_relation(int A,int B) {
  94. struct nodo *nodo_a,*nodo_b;
  95. if(todos[A] == NULL) { // Si no existe A lo inicializamos
  96. todos[A] = calloc(sizeof(struct nodo),1);
  97. todos[A]->id  = A;
  98. }
  99. if(todos[B] == NULL) { // Si no existe B lo inicializamos
  100. todos[B] = calloc(sizeof(struct nodo),1);
  101. todos[B]->id  = B;
  102. }
  103. nodo_a = todos[A];
  104. nodo_b = todos[B];
  105. if(!nodo_a->arbol && !nodo_b->arbol){ // Si ambos arboles son NULL los inicializamos
  106. nodo_a->arbol = agregar_valor_arbol(nodo_a->arbol,nodo_a);
  107. nodo_a->arbol = agregar_valor_arbol(nodo_a->arbol,nodo_b);
  108. }
  109. else {
  110. if(nodo_a->arbol && !nodo_b->arbol) { //Si el arbol de A es valido y el de B no, agregamos B al arbol de A
  111. nodo_a->arbol =agregar_valor_arbol(nodo_a->arbol,nodo_b);
  112. }
  113. else {
  114. if(!nodo_a->arbol && nodo_b->arbol){ //Si el arbol de B es valid y el de A no, agregamo A al arbol de B
  115. nodo_b->arbol =agregar_valor_arbol(nodo_b->arbol,nodo_a);
  116. }
  117. else{// En este punto ambos arboles son validos
  118. if(nodo_a->arbol != nodo_b->arbol) { //Validamos si ambos arboles son distintos
  119. if(nodo_a->arbol->total < nodo_b->arbol->total) { // Evaluamos cual es el arbol con mejor coste de fusion
  120. nodo_b->arbol = funciona_arbol(nodo_b->arbol,nodo_a->arbol); //Fucionamos el arbol de A en el arbol de B
  121. }
  122. else {
  123. nodo_a->arbol = funciona_arbol(nodo_a->arbol,nodo_b->arbol); //Fucionamos el arbol de B en el arbol de A
  124. }
  125. }
  126. }
  127. }
  128. }
  129. }
  130.  
  131. //Fucinamos el arbol B en el arbol A, y eliminamos B nodo por nodo y finalmente liberamos la estructura Arbol que usamos
  132. struct arbol *funciona_arbol(struct arbol *A,struct arbol *B) {
  133. int i = 0;
  134. while(i<B->total) {
  135. B->nodos[i];
  136. A = agregar_valor_arbol(A,B->nodos[i]->valor);
  137. free(B->nodos[i]);
  138. i++;
  139. }
  140. free(B);
  141. return A;
  142. }
  143.  
  144.  
  145. //Evaluar si existe un camino valido de A a B, se reduce a validar si estan en el mismo Arbol o no
  146. bool existe_salto(int A,int B) {
  147. struct nodo *nodo_a = NULL,*nodo_b =NULL;
  148. nodo_a = todos[A];
  149. nodo_b = todos[B];
  150. return (nodo_a->arbol == nodo_b->arbol);
  151. }
  152.  
  153.  
  154. //Funcion auxiliar para crear un nodo de arbol
  155. struct nodo_arbol *crear_nodo_arbol(struct nodo_arbol *padre,struct nodo *valor) {
  156. struct nodo_arbol *n = calloc(sizeof(struct nodo_arbol),1);
  157. if(n == NULL) {
  158. printf("Error de Memoria\n");
  159. exit(0);
  160. }
  161. n->padre = padre;
  162. n->valor = valor;
  163. return n;
  164. }
  165.  
  166. //Agregamos un valor al arbol
  167. struct arbol *agregar_valor_arbol(struct arbol *arbol,struct nodo *valor) {
  168. struct nodo_arbol *temp,*pivote;
  169. int derecho = 0;
  170. if(arbol) {
  171. temp =arbol->raiz;
  172. while(temp != NULL) {
  173. pivote = temp;
  174. if(valor->id > temp->valor->id) {
  175. temp = temp->derecho;
  176. derecho = 1;
  177. }
  178. else {
  179. temp = temp->izquierdo;
  180. derecho = 0;
  181. }
  182. }
  183. temp = crear_nodo_arbol(pivote,valor);
  184. if(derecho) {
  185. pivote->derecho = temp;
  186. }
  187. else {
  188. pivote->izquierdo = temp;
  189. }
  190. valor->arbol = arbol;
  191. arbol->nodos = realloc(arbol->nodos,sizeof(struct nodo*)*(arbol->total+1));
  192. arbol->nodos[arbol->total] = temp;
  193. }
  194. else {
  195. arbol = calloc(sizeof(struct arbol),1);
  196. arbol->raiz = crear_nodo_arbol(NULL,valor);
  197. arbol->nodos = realloc(arbol->nodos,sizeof(struct nodo_arbol*)*(arbol->total+1));
  198. arbol->nodos[arbol->total] = arbol->raiz;
  199. valor->arbol = arbol;
  200. }
  201. arbol->total++;
  202. return arbol;
  203. }