Autor
|
Tema: Ayuda. Programas para reconocer Números palíndromos. (Leído 13,070 veces)
|
theluigy13etv
Desconectado
Mensajes: 179
Primero se hace, después se mejora
|
H ola a todos. Estaba practicando un problema que tomaron en la competencia de programación de la ACM. El examen pertenece a la fase regional en América del Sur. La dirección es la siguiente: http://livearchive.onlinejudge.org/external/23/2389.pdf
Básicamente el problema consiste en ingresar numero n. (0<n<50000) No es necesario validar. Y el programa debe de determinar si dicho número es palíndromo (capicúa) en alguna base b (la base 2<=b<=16). El programa finaliza si el número n ingresado es 0 . EJEMPLO DE ENTRADA: 17 19 0 EJEMPLO DE SALIDA: Number 17 is palindrom in basis 2 4 16 Number 19 is not palindrom Ahora les va mi código. La verdad que no le encuentro ningún error pero cuando lo mando para que me lo revisen a la página de la ACM. Me lo rechazan diciendo que es incorrecto: # include <iostream>
using namespace std;
int main() { int n; int aux, r, b, N, P; int inv; int ac[15]; while(1) { cin>>n; if(n == 0) break;
int cont = 0;
for(b=2; b<=16; b++) { aux = n; N = 0; P = 1; do{ r = aux % b; aux = aux / b; N = N + r * P; P = P * 10; }while(aux != 0);
inv = 0; aux = N; do{ r = aux % 10; inv = inv * 10 + r; aux = aux / 10; }while(aux !=0 ); if(inv == N) { cont++; ac[cont] = b; } } if(cont>0) { cout<<"Number "<<n<<" is palindrom in basis"; for(int i=1; i<=cont; i++) { cout<<" "<<ac[i]; } cout<<"\n"; } else { cout<<"Number "<<n<<" is not palindrom\n"; } } }
|
|
« Última modificación: 9 Enero 2012, 04:03 am por theluigy13etv »
|
En línea
|
|
|
|
soyloqbuskas
Desconectado
Mensajes: 219
¡El conocimiento es de todos!
|
Ooook! ya le he hechado un vistazo al codigo y es !CORRECTO¡, lo unico que los numeros con una base superior a 10 (11-16) tienen numero representados por letras y esos como palindromos no los detecta. En el ejemplo que te puse antes... AB1BA es capicua por las letras pero al introducir el numero en base 10 (700858) y luego al hacer el cambio a base 16 el numero que sale es: 10 11 1 11 10 : no es capicua A B 1 B A : si es capicua Entonces este tipo de numero nos los coge. Pero vamos si esto es una practica, el profesor no creo que te la haya tirado por esto ya que solucionar esto es un poco enrevesado. Yo creo que el verdadero motivo por el que te la ha tirado es por que el enunciado dice: Básicamente el problema consiste en ingresar numero n. (0<n<50000) y tu codigo pone: Cuando en realidad deberia poner: if(n==0 || n>=50000) break; Ademas de que el codigo no esta comentado y no usas variables con nombres significativos.... Y bueno este es el codigo que yo he hecho para tu programa. Aun asi tiene el mismo fallo que el tuyo de los numeros representados en una base mayor que 10... #include <iostream>
using namespace std;
int cambioBase(int n, int base) { // Funcion para el cambio de base int n_base=0, coef=1; while (n!=0) { n_base+=coef*(n%base); coef*=10; n/=base; } return n_base; }
bool esCapicua (int numero){ //Funcion para comprobar si un numero es capicua bool resultado=false; int capb=numero; int capd=0; int capc=0;
while(capb!=0){ capc=capb%10; capd=capd*10+capc; capb=capb/10; } if(capd==numero) resultado = true; return resultado; }
int main(){ //Declaracion de variables int numero, aux1; int baseIni=2; int baseFin=16; bool capicua=false; bool check =false; //Codigo principal cout<<"Escribe un numero en base 10: "; cin>>numero; if(numero==0 || numero>=50000){ // Si el numero introducido exede el limite finalizo el programa cout<<"El numero introducido supera el limite\n"; system("pause"); return 0; } for (baseIni; baseIni <= baseFin; baseIni++){ //Comprobamos si el numero es capicua para todas las bases aux1 = cambioBase(numero, baseIni); //Cambio de base capicua = esCapicua(aux1); //es capicua? if(capicua){ //Si es capicua imprimios el resultado y ponemos check a true cout<<"\nEl numero: "<<numero<<" es capicua para la base: "<<baseIni<<"\n"; capicua = false; check = true; } } //Si ningun numero es capicua check seguira con su valor inicial (false) if(!check) cout<<"\nEl numero: "<<numero<<" no es capicua para ninguna base entre 2-16\n";
system("pause"); return 0; }
Espero haberte servido de ayuda, un saludo!
|
|
« Última modificación: 9 Enero 2012, 14:08 pm por soyloqbuskas »
|
En línea
|
"Si tienes 1 manzana y yo tengo otra manzana... y las intercambiamos, ambos seguiremos teniendo 1 manzana. Pero...si tu tienes 1 idea y yo tengo otra idea... y las intercambiamos, ambos tendremos 2 ideas."
George Bernard Shaw
|
|
|
theluigy13etv
Desconectado
Mensajes: 179
Primero se hace, después se mejora
|
Muchas gracias por tomarte tu tiempo. Me olvidaba que los números ingresados era solo números en base 10. Y estos recién debían pasarse a base 2, 3, ... 16. Creo que el problema está cuando se tratan bases mayores que 10. Y al inicio puse: Esto era porque el programa terminaba al ingresar un 0. Ahhh. Y para este problema no nos piden que sea interactivo ni mostrar mensajes al principio. Además no nos piden validar la entrada de los números, sino debemos de sobreentender que el número ingresado cumple la regla 0<n<50000 No es necesario validar Muchas gracias por tomarte tu tiempo!!!
|
|
|
En línea
|
|
|
|
Xandrete
Desconectado
Mensajes: 210
|
¡Hola! El problema que cita soyloqbuskas, que en realidad no es exactamente como lo describe, es un poco más grave, pero aún así no es tan enrevesado a la hora de solucionarlo. Digo que no es exactamente como lo describe porque, por ejemplo, al hacer el cambio de 27 a hexadecimal (sí, sé que no es capicúa en hexadecimal), mediante el bucle que usas no obtendrías N = 111 (es decir, 1 11 junto, que correspondería a 1B), sino que te daría 21 (0+ 11 + 10*1). Doy unas ideas para solucionarlo (no pongo código porque ahora mismo no tengo tiempo, mañana lo detallo un poco más, si puedo): Lo que puedes hacer es, al realizar la conversión de un número decimal a otra base, guardar cada dígito en una nueva posición de un vector (previo "include <vector>") o array, en lugar de guardarlo como int. Así, en el ejemplo de 700858 (AB1BA), al hacer el cambio a base 16 tendrías un vector así: [10,11,1,11,10] y aquí es donde comparas la primera posición con la última, la segunda con la penúltima, y así sucesivamente (la forma de hacerlo puede ser distinta en función de si usas vector o array... mi consejo: usa vector, te facilita bastante la vida). Evidentemente, para esta solución tienes que cambiar la rutina que realiza el cambio de base y también la rutina que comprueba si un número es capicúa. Bueno, no usas rutinas aparte del main... es una de las cosas que quería comentarte (lo haré más adelante)... Otra solución, más conservadora con lo que tienes, es hacer lo siguiente: si la base es superior a 10, tu variable P (o la variale coef del programa soyloqbuskas) la multiplicas por 100 en vez de por 10, y la comprobación de si es capicúa o no la haces comparando dígitos dos a dos (el primer par con el último par, el segundo par con el penúltimo par y así), y si la base es menor o igual a 10, lo haces tal y como lo haces ahora (digo más conservadora porque seguirías usando un int). Me suscribo a lo que dice soyloqbuskas. Usa nombre de variables significativos. Lo de la falta de comentarios no lo encuentro tan grave, porque por lo que veo, el problema es uno de estos típicos de los jueces automáticos, a los que les mandas el código, te lo compila, le aplican juegos de prueba y te dicen si el programa cumple con las espectativas o no (vamos, como el de la Universidad de Valladolid, http://uva.onlinejudge.org/, o el de la Universitat Politècnica de Catalunya, https://www.jutge.org/ - te los pongo por si quieres echarles un vistazo también, van muy bien para prácticar y ganar flexibilidad a la hora de programar). O sea, que en realidad no se los mira nadie, ¿no? Y lo que sí ha hecho soyloqbuskas en su código pero no te ha sugerido explicitamente es... usar funciones. ¡Usa funciones! No pongas un pastuño de código en el main. Si usas funciones, puedes probar partes de tu programa individualmente, ir poco a poco. Ya sabes... divide y vencerás. Bueno, ¡saludos! Espero haberte ayudado también. EI: juntando mensajes.Bueno, tal como prometí que intentaría, vengo con algo de código para intentar ayudar: #include <iostream> #define NUMMAXOFDIGITS 17 using namespace std; bool isPalindrome(int* vector) { int size = vector[0]; ++vector; bool isPal = true; int n = 0; while (n < size/2 and isPal) { isPal = vector[n] == vector[size-n-1]; ++n; } return isPal; } void dec2basB(int dec, int B, int* result) { int n = 1; while (dec > 0) { result[n] = dec%B; dec/=B; ++n; } result[0] = n - 1; } int main() { /* ... */ }
Como ves, sólo he programado las funciones críticas que se utilizan en el programa. No he hecho el main, lo dejo para ti (es sencillo). Vamos por partes: - Utilizo arrays. Eso me lleva a utilizar un "formato" o estructura especial para conocer el tamaño "útil" del array (es decir, el número de posiciones con información realmente útil). Lo que he hecho es emplear la primera posición (la 0) para indicar el número de elementos útiles que le siguen.
- Las posiciones de menos peso de los arrays (excepto la 0, que es la que indica el tamaño) la ocupan los dígitos de menos peso de un número. Así, el número 3432, de la forma que lo he montado, se representaría mediante un array así: [4,2,3,4,3]
- Teniendo en cuenta los dos puntos anteriores, no creo que tengas ningún problema en entender las funciones isPalindrome y dec2Bas2. Lo que sí, ten en cuenta, que el array donde guarda dec2Bas el resultado se lo tienes que pasar como parámetro y debe tener como mínimo NUMMAXOFDIGITS (en este caso es 17 porque el número máximo de dígitos sería el del mayor número que puede haber a la entrada en la base menor, o sea, 50000 y 2 respectivamente). Si no es así, ya dirás algo
Por supuesto, ¡esto es sólo una manera de hacerlo! Otra forma sería usar vector, en cuyo caso no necesitarías almacenar el número de elementos al principio de la secuencia ya que el tipo vector ya realiza un seguimiento de los números presentes en la secuencia. O listas. O usar un int de la forma que sugerí en el post anterior (aunque esto último es un poco más farragoso, es factible también). Bueno, eso es todo. Si tienes dudas, postea. ¡Saludos! P.S. Ya he probado la función (las 2). El resultado es correcto. De hecho, sirve también para entradas más grandes de 50000.
|
|
« Última modificación: 24 Enero 2012, 15:48 pm por Eternal Idol »
|
En línea
|
|
|
|
ghastlyX
Ex-Staff
Desconectado
Mensajes: 1.900
|
En los comentarios no estoy del todo de acuerdo según qué busque. Si es un entreno para concursos de programación, hay muchos de esos consejos que no se suelen utilizar. Por ejemplo, rara vez se hacen comentarios, las variables suelen tener nombres cortos poco descriptivos (para otros programadores que lo lean al menos) y a veces se usan pocas funciones. Especialmente en los nombres de las variables, yo que participo a menudo suelo utilizar para casi todo nombres de como mucho unas cinco letras, ya que se tarda menos en escribirlo y en estos concursos la velocidad es importante. Además, aunque para otros sean poco descriptivos, son nombres genéricos que utilizo siempre para los mismos conceptos y por lo tanto para mí son descriptivos. Pongo una solución que he hecho para el problema y que me ha dado Accepted en Live Archive. La he hecho como si estuviera haciendo un concurso y he tardado menos de cinco minutos: #include <iostream> #include <vector> #include <algorithm> using namespace std; string c = "0123456789ABCDEF"; int main() { int n; while (cin >> n and n > 0) { vector<int> base; for (int i = 2; i <= 16; ++i) { string s; int x = n; while (x > 0) { s += c[x%i]; x /= i; } string r = s; reverse(s.begin(), s.end()); if (s == r) base.push_back(i); } if (base.size() == 0) cout << "Number " << n << " is not palindrom" << endl; else { cout << "Number " << n << " is palindrom in basis"; for (int i = 0; i < base.size(); ++i) cout << " " << base[i]; cout << endl; } } }
Por eso digo que a veces uno se suele saltar esos principios para ganar velocidad. Obviamente, en códigos más largos es sin duda necesario usar funciones adecuadamente, poner nombres descriptivos, etc. Me refiero únicamente a concursos.
|
|
|
En línea
|
|
|
|
Xandrete
Desconectado
Mensajes: 210
|
Por ejemplo, rara vez se hacen comentarios, las variables suelen tener nombres cortos poco descriptivos (para otros programadores que lo lean al menos) y a veces se usan pocas funciones. Especialmente en los nombres de las variables, yo que participo a menudo suelo utilizar para casi todo nombres de como mucho unas cinco letras, ya que se tarda menos en escribirlo y en estos concursos la velocidad es importante. Además, aunque para otros sean poco descriptivos, son nombres genéricos que utilizo siempre para los mismos conceptos y por lo tanto para mí son descriptivos.
¡Hola ghastlyX! Nunca he participado en concursos (y en general, no he participado en ninguna prueba contrarreloj de retos de programación, salvo en exámenes). Suelo programar para jueces online y de vez en cuando visito Topcoder (para resolver retos en modo práctica... nada de competiciones por ahora). En ningún caso podré dar un criterio más fiable que el tuyo pues carezco de la experiencia que tienes tú en el ámbito de los concursos. De todas maneras, la mayoría de las cosas que dices me parecen perfectamente lógicas y aceptables en un evento de competición, coincido en ellas. Lo que no veo tan claro es el tema de ahorrar funciones. ¿Crees que compensa ahorrarse escribir cabeceras de funciones sólo para ganar velocidad? Este problema de los palíndromos es muy fácil, y puedes hacerlo todo en el main a la primera. Pero hay problemas mucho más diabólicos que éste, y si empiezas a hacerlo todo en el main y te equivocas en algo, puede ser mucho más difícil depurar el error. Además, muchas veces es inevitable cuando tienes que usar algoritmos cuya implementación más natural sea la recursiva (por ejemplo, recorridos por árboles). ¿No crees que sería mejor adoptar una postura intermedia? Por ejemplo, usar todas las funciones que hagan falta y, para ahorrarse el paso de parámetros, emplear variables globales. En fin, son cosas de un enamorado de las funciones, tampoco quiero abrir un debate sobre ese tema >.< Por cierto, nice code ¡Saludos!
|
|
|
En línea
|
|
|
|
ghastlyX
Ex-Staff
Desconectado
Mensajes: 1.900
|
No me refería a no usar funciones. Cuando he puesto pocas me refería a cosas del estilo a que no se piensa en temas de portabilidad, reutilización y otras cosas de estas que predica la Ingeniería del Software. Las funciones se suelen usar cuando son útiles para el código: se hace más corto usándola, más sencillo, más natural, etc.
Simplemente me refería a que si en algunos casos es indiferente, como por ejemplo en el código de este problema, suele ser habitual comerse la función.
|
|
|
En línea
|
|
|
|
Xandrete
Desconectado
Mensajes: 210
|
Entonces coincido plenamente
|
|
|
En línea
|
|
|
|
theluigy13etv
Desconectado
Mensajes: 179
Primero se hace, después se mejora
|
Gracias a todos.. Pronto subo mi solución a mi manera. Lo que no entiendo es qué significa esto: while (cin >> n and n > 0)
|
|
|
En línea
|
|
|
|
Xandrete
Desconectado
Mensajes: 210
|
Es un bucle con una condición doble. Por un lado, se lee del buffer de entrada, se hace la conversión de caracteres a entero y se guarda en n el resultado. Si falla este proceso en algún punto (se lee EOF - End Of File- , o lo que se lee no se puede convertir a entero) se sale del bucle. Por otro lado, se comprueba si el valor de n es mayor que 0. Si no lo es, se sale del bucle (una entrada de 0 debía producir el fin del programa, según tu enunciado). En C++ las condiciones siempre se leen de izquierda a derecha, por lo que siempre podrás estar seguro de que se lee el valor antes de comprobar si es mayor que 0. Una forma alternativa de implementarlo es la siguiente: int n; cin >> n; while (n > 0) { // CODIGO DEL BUCLE cin >> n; }
De la manera que te propuso ghastlyX queda más compacto. Saludos
|
|
« Última modificación: 24 Enero 2012, 15:48 pm por Xandrete »
|
En línea
|
|
|
|
|
Mensajes similares |
|
Asunto |
Iniciado por |
Respuestas |
Vistas |
Último mensaje |
|
|
Reconocer imágenes con números
Programación Visual Basic
|
icisneros
|
7
|
10,106
|
5 Junio 2008, 23:49 pm
por icisneros
|
|
|
Problema de strings: Palindromos.
Ejercicios
|
j retirado
|
7
|
10,092
|
22 Julio 2009, 19:43 pm
por Ragnarok
|
|
|
[Problema] Programa para averiguar números pares entre 2 números
Programación Visual Basic
|
Dreamaker
|
3
|
5,847
|
21 Mayo 2010, 23:45 pm
por Shell Root
|
|
|
Programa para distinguir palindromos:
« 1 2 »
Programación C/C++
|
Error 404:
|
12
|
8,223
|
27 Junio 2014, 18:16 pm
por Eternal Idol
|
|
|
Programa para detectar palindromos
Programación C/C++
|
Error 404:
|
7
|
7,578
|
6 Septiembre 2014, 09:37 am
por Error 404:
|
|