quien me ayuda con este programa!!!!numeros!!!

Iniciado por akiss, 4 Marzo 2012, 04:13 AM

0 Miembros y 1 Visitante están viendo este tema.

akiss

La siguiente función determina si un número natural es primo.

int primo(long n)
{
  // si n es primo (asume sqrt() de math.h)
 
  int p = 1;  // si n es primo -asume si
  long d; // posibles divisores

  for (d = 2; d <= sqrt(n); d++)
      if (n % d == 0) p = 0;;

  if (n < 2) p = 0;

  return p;
}

El número 197 se dice que es un primo circular porque todas las rotaciones de sus dígitos, 197, 971 y 719, son a su vez primos.

¿Podría redactar una función que encuentre la cantidad de primos circulares menores que t? [Asuma e invoque la función primo().]

Xandrete

Intenta algo. La premisa aquí es que no se hacen tareas. Si posteas alguna aproximación (aunque sea errónea) al problema, te ayudaremos. En el fondo, sólo necesitas una función que te sitúe el dígito de mayor peso de n en el lugar de las unidades. Inténtalo.

Por otro lado, te puedo decir que la función para detectar si un número es primo se puede mejorar. Sólo necesitas hacer el módulo por los números impares, una vez ya has comprobado que no es divisible por dos. De esta manera, te ahorras sqrt(n)/2 divisiones en el peor de los casos (que es que n sea efectivamente primo). Se puede optimizar más aún, teniendo en cuenta que a partir del 3 todo número primo p cumple que p = 6*k +- 1 para todo k perteneciente a los naturales. Por ejemplo, el 47 es primo y es igual al 6*8-1. El 37 es primo y es igual a 6*6 + 1. De este modo, el número de divisiones que realizas estará acotado por sqrt(n)/3. En un número primo de 8 cifras, la diferencia radica entre hacer unas 10000 divisiones (versión que has posteado), 5000 divisiones (versión que sólo comprueba con los divisores impares) y 3000 divisiones (la última versión que te he propuesto). Aproximadamente, por supuesto. Es sólo para que te hagas una idea.

Sin embargo, lo más óptimo si conoces la cota superior de n (el número máximo para el cual te van a preguntar si es primo o no) es el método conocido como criba de Eratóstenes (busca en la Wiki).

¡Saludos!

Xandrete

#2
Deberías dividir tu problema en subproblemas. De momento tienes aislada la parte para saber si un número es primo. Lo ideal ahora sería que pensaras en un módulo o función que te calculara la órbita de un número. Si lo integras todo en el main, el código será más difícil de leer y de corregir.

Aquí una propuesta de función:

int orbit(int n) {
int n_10 = n/10;
int orbit = n%10;
n = n_10;
while (n != 0) {
orbit *= 10;
n /= 10;
}
orbit += n_10;
return orbit;
}


Tu idea para obtener la "órbita" de un número (convirtiéndolo en una cadena y efectuando los desplazamientos correspondientes) es también válida.

Tu código es un poquitín chapuza por los siguientes motivos. Imagínate que evalúas el 23423426. Tu código comprueba la primera vez que no es primo, pero igualmente haces la rotación y vuelves a comprobar si es primo, y así 8 veces. Es evidente que si una sola de las órbitas del número  no es prima, el número no puede ser primo circular y puedes parar y pasar a evaluar el siguiente número. Además, si tienes 7777, harás 4 comprobaciones, cuando está claro que es totalmente innecesario (da igual las rotaciones que le apliques a 7777, seguirá siendo el mismo número y por tanto, basta con una sola comprobación. Y por último, si tienes que un número es primo circular, esta claro que todos los números de su órbita son primos circulares también, y cuando llegues a ellos no haría falta hacer todas las comprobaciones de nuevo. Aquí un código que he hecho para este mismo problema en que tengo en cuenta todo esto:

#include <stdio.h>
#include <stdlib.h>
#include <math.h>

int k = 0;

int isPrime(int n) {
int sqrt_n = (int) sqrt(n);
int lim = (sqrt_n+1)/6;
int i;
if (n==2 || n==3) return 1;
if (n==1 || !(n%2) || !(n%3)) return 0;
for (i = 1; i <= lim; ++i) {
if (!(n%(6*i-1)) || !n%(6*i+1)) return 0;
++k;
}
return 1;
}

int orbit(int n) {
int n_10 = n/10;
int orbit = n%10;
n = n_10;
while (n != 0) {
orbit *= 10;
n /= 10;
}
orbit += n_10;
return orbit;
}

int main() {
int n,prime,i,j,s,q;
int* taken;
scanf("%d",&n);
taken = malloc(n*sizeof(int));
for (i = 0; i < n; ++i) taken[i] = 0;

q = 1;
for (i = 3; i < n; i += 2) {
if (!taken[i]) {
j = i;
s = 0;
do {
if (j < n) {
taken[j] = 1;
++s;
}
prime = isPrime(j);
j = orbit(j);
} while (prime && j!=i);
if (prime) q += s;
}
}
printf("%d\n",q);
return 0;
}

akiss