Fracciones egipcias


20

Visión general:

De Wikipedia : Una fracción egipcia es la suma de fracciones unitarias distintas. Es decir, cada fracción en la expresión tiene un numerador igual a 1 y un denominador que es un entero positivo, y todos los denominadores difieren entre sí. El valor de una expresión de este tipo es un número racional positivo a / b. Cada número racional positivo puede ser representado por una fracción egipcia.

Desafío:

Escriba la función más corta que devolverá los valores de todos los denominadores para el conjunto más pequeño de fracciones unitarias que suman una fracción dada.

Reglas / Restricciones:

  • La entrada será dos valores enteros positivos.
    • Esto puede ser en STDIN, argv, separados por una coma, el espacio delimitado, o cualquier otro método que prefiera.
  • El primer valor de entrada será el numerador y el segundo valor de entrada el denominador.
  • El primer valor de entrada será menor que el segundo.
  • El resultado puede incluir uno o varios valores que exceden las limitaciones de memoria de su sistema / idioma (RAM, MAX_INT o cualquier otra restricción de código / sistema que exista). Si esto sucede, simplemente trunca el resultado al valor más alto posible y ten en cuenta que de alguna manera (es decir ...).
  • La salida debe poder manejar un valor de denominador de hasta al menos 2,147,483,647 (2 31 -1, con signo de 32 bits int).
    • Un valor más alto ( long, etc.) es perfectamente aceptable.
  • La salida debe ser una lista de todos los valores de los denominadores del conjunto más pequeño de fracciones unitarias encontradas (o las fracciones mismas, es decir 1/2).
  • La salida se ordenará ascendente de acuerdo con el valor del denominador (descendente por el valor de la fracción).
  • La salida se puede delimitar de la forma que desee, pero debe haber algún carácter intermedio para diferenciar un valor del siguiente.
  • Este es el código de golf, por lo que gana la solución más corta.

Ejemplos:

  • Entrada 1:

    43, 48

  • Salida 1:

    2, 3, 16

  • Entrada 2:

    8/11

  • Salida 2:

    1/2 1/6 1/22 1/66

  • Entrada 3:

    5 121

  • Salida 3:

    33 121 363


Entrada / Salida 2 debe ser 8, 11y 2, 6, 22, 66¿verdad?
mellamokb

2
Una posible sugerencia, para eliminar la abiguidad, sería requerir el conjunto más pequeño de fracciones unitarias con el mínimo denominador final. Por ejemplo, 1/2 1/6 1/22 1/66sería preferible 1/2 1/5 1/37 1/4070para la entrada 8/11.
primo

2
Sugiero agregar 5/121 = 1/33+1/121+1/363a los casos de prueba. Todos los programas codiciosos (incluido el mío) dan 5 fracciones para ello. Ejemplo tomado de Wikipedia .
ugoren

1
@primo Creo que si hay varios mínimos, lo que se pueda encontrar sería aceptable. Si se puede escribir un algoritmo con menos caracteres como resultado, no quisiera obstaculizar esa solución.
Gaffi

1
Obtuve +1 desde que realmente aprendí sobre fracciones egipcias en un curso de Historia de las Matemáticas (y tuve que hacer cálculos matemáticos con ellas, además de encontrar sumas fraccionarias como este problema). Un desafío agradable y creativo.
mbomb007

Respuestas:


6

Lisp común, 137 caracteres

(defun z(n)(labels((i(n s r)(cond((= n 0)r)((< n(/ 1 s))(i n(ceiling(/ 1 n))r))(t(i(- n(/ 1 s))(1+ s)(cons s r))))))(reverse(i n 2'()))))

(z 43/48) -> (2 3 16)

(z 8/11) -> (2 5 37 4070)

(z 5/121) -> (25757 763309 873960180913 1527612795642093418846225)

¡No hay necesidad de preocuparse por números grandes o por manejar la notación fraccional!


(defun z (n) (etiquetas ((i (nsr) (cond ((= n 0) r) ((<n (/ 1 s)) (in (techo (/ 1 n)) r)) (t ( i (- n (/ 1 s)) (1+ s) (cons sr)))))) (inversa (en 2 '())))) (z 43/48) Mostrar no dar como resultado tio ... ¿Qué tengo que usar para imprimir el resultado?
RosLuP

1
(print (z 103/333)) devuelve una lista de 5 números pero existiría una lista de 4 números como: 1 / 4,1 / 18,1 / 333,1 / 1332. Entonces, la función anterior no devolvería el mínimo.
RosLuP

8

Python 2, 169 167 caracteres

x,y=input()
def R(n,a,b):
 if n<2:return[b/a][b%a:]
 for m in range((b+a-1)/a,b*n/a):
  L=R(n-1,a*m-b,m*b)
  if L:return[m]+L
n=L=0
while not L:n+=1;L=R(n,x,y)
print L

Toma argumentos separados por comas en stdin e imprime una lista de python en stdout.

$ echo 8,11 | ./egypt.py 
[2, 5, 37, 4070]

2
1. Creo que puede guardar dos caracteres utilizando la pestaña en el segundo nivel de sangría. 2. El script no indica truncamiento debido a que se exceden las limitaciones de memoria del sistema.
breadbox

En Tio Su código se queda sin memoria por solo 103/45533
RosLuP

En cambio, en Ideone su código entra en error de tiempo de ejecución para la misma entrada 103,45533: Error de tiempo de ejecución #stdin #stdout #stderr 0.89s 99264KB
RosLuP

4

PHP 82 bytes

<?for(fscanf(STDIN,"%d%d",$a,$b);$a;)++$i<$b/$a||printf("$i ",$a=$a*$i-$b,$b*=$i);

Esto podría hacerse más corto, pero el numerador y el denominador actuales deben mantenerse como números enteros para evitar el error de redondeo de coma flotante (en lugar de mantener la fracción actual).

Uso de la muestra:

$ echo 43 48 | php egyptian-fraction.php
2 3 16
$ echo 8 11 | php egyptian-fraction.php
2 5 37 4070

Operador de coma emulado como argumentos inútiles para printf? Debería guardar este truco en alguna parte.
Konrad Borowski

1
Estoy bastante seguro de que este es un algoritmo codicioso , por lo que no siempre dará el conjunto más pequeño de fracciones. Si lo ejecuta con una entrada como 5 121o 31 311, dará la respuesta incorrecta (después de mucho tiempo).
grc

@grc 31/311 -> {a [1] -> 11, a [2] -> 115, a [3] -> 13570, a [4] -> 46422970}
Dr. belisarius

4

C, 163 177 caracteres

6/6 : Por fin, el programa ahora maneja correctamente el truncamiento en todos los casos. Tomó muchos más caracteres de los que esperaba, pero valió la pena. El programa debe cumplir al 100% los requisitos del problema ahora.

d[99],c,z;
r(p,q,n,i){for(c=n+q%p<2,i=q/p;c?d[c++]=i,0:++i<n*q/p;)q>~0U/2/i?c=2:r(i*p-q,i*q,n-1);}
main(a,b){for(scanf("%d%d",&a,&b);!c;r(a,b,++z));while(--c)printf("%d\n",d[c]);}

El programa toma el numerador y el denominador en la entrada estándar. Los denominadores se imprimen en salida estándar, uno por línea. La salida truncada se indica imprimiendo un denominador cero al final de la lista:

$ ./a.out
2020 2064
2
3
7
402
242004

$ ./a.out
6745 7604
2
3
19
937
1007747
0

Los denominadores en el segundo ejemplo suman 95485142815/107645519046, que difiere de 6745/7604 en aproximadamente 1e-14.


De nuevo, creo que este es un algoritmo codicioso.
grc

El bucle más externo explora todas las respuestas posibles de N denominadores antes de comenzar a probar las respuestas de N + 1 denominadores. Puede llamarlo codicioso, supongo, pero creo que cumple con el problema planteado.
breadbox

Lo siento, lo retiro. No sigue la solución codiciosa, pero he descubierto que no es completamente precisa para alguna entrada ( 31 311por ejemplo).
grc

31 311se desborda, pero el programa no puede marcarlo.
breadbox

3

Python, 61 caracteres

Entrada de STDIN, separada por comas.
Salida a STDOUT, nueva línea separada.
No siempre devuelve la representación más corta (por ejemplo, para 5/121).

a,b=input()
while a:
    i=(b+a-1)/a
    print"1/%d"%i
    a,b=a*i-b,i*b

Caracteres contados sin nuevas líneas innecesarias (es decir, unir todas las líneas dentro del whileuso ;).
La fracción es a/b.
iestá b/aredondeado, así que lo sé 1/i <= a/b.
Después de imprimir 1/i, lo reemplazo a/bcon a/b - 1/i, que es (a*i-b)/(i*b).


Quiero votar esto, ya que es muy pequeño, ¡pero solo falta esa pieza!
Gaffi

2
Quiero arreglar esta pieza, pero no será tan pequeña ... Tengo la sensación de que reinventaré la solución de Keith Randall.
ugoren

2

C, 94 bytes

n,d,i;main(){scanf("%i%i",&n,&d);for(i=1;n>0&++i>0;){if(n*i>=d)printf("%i ",i),n=n*i-d,d*=i;}}

Pruébalo en línea

editar: se publicó una versión más corta del código en los comentarios, así que lo reemplacé. ¡Gracias!


2
Hola y bienvenidos al sitio! Esta es una competencia de código de golf , por lo que el objetivo es hacer que su código sea lo más breve posible . Parece que hay muchas cosas que podrías hacer para acortar tu código. Por ejemplo, podría eliminar todos los espacios en blanco innecesarios de su respuesta.
DJMcMayhem

@DJMcMayhem Gracias señor, entendido y hecho.
う ち わ 密 か

Hola, bienvenido a PPCG! ¿Podría agregar un enlace TryItOnline con código de prueba para los casos de prueba en el desafío? Además, algunas cosas que podría jugar al golf: for(i=2;n>0&&i>0;i++)pueden ser for(i=1;n>0&++i>0;); los corchetes del bucle for se pueden quitar (porque solo tiene el ifinterior); d=d*i;puede ser d*=i;; y no estoy del todo seguro, pero creo que #include <stdio.h>puede estar sin espacios: #include<stdio.h>. Ah, y puede ser interesante leer Consejos para jugar golf en C y Consejos para jugar golf en <todos los idiomas>
Kevin Cruijssen

@KevinCruijssen Gracias por los consejos.
う ち わ 密 か



0

AXIOM, 753 bytes

L==>List FRAC INT
macro  M(q)==if c<m or(c=m and m<999 and reduce(max,map(denom,q))<xv)then(m:=c;a:=q;xv:=reduce(max,map(denom,a)))
f(x,n)==(y:=x;a:L:=[];c:=0;q:=denom x;q:=q^4;for i in n.. repeat((c:=c+1)>50=>(a:=[];break);1/i>y=>1;member?(1/i,a)=>1;a:=concat(a,1/i);(y:=y-1/i)=0=>break;numer(y)=1 and ~member?(y,a)=>(a:=concat(a,y);break);(i:=floor(1/y))>q=>(a:=[];break));a)
h(x:FRAC INT):L==(a:L:=[];x>1=>a;numer(x)=1=>[x];n:=max(2,floor(1/x));xv:=m:=999;d:=denom x;zd:=divisors d;z:=copy zd;for i in 2..30 repeat z:=concat(z,i*zd);d:=min(10*d,n+9*m);for i in n..d repeat((c:=maxIndex(b:=f(x,i)))=0=>1;c>m+1=>1;M(b);v:=reduce(+,delete(b,1));for j in z repeat((c:=1+maxIndex(q:=f(v,j)))=1=>1;member?(b.1,q)=>1;q:=concat(b.1,q);M(q)));reverse(sort a))

La idea sería aplicar el "Algoritmo codicioso" con diferentes puntos iniciales y guardar la lista que tiene una longitud mínima. Pero no siempre encontraría la solución mínima con menos diferido: "la matriz A será menor que la matriz B si y solo si A tiene pocos elementos de B, o si el número de elementos de A es igual al número de elementos de B , que A es menor que B si el elemento más pequeño de A es mayor como número, que el elemento más pequeño de B ". Sin golf y prueba

-- this would be the "Greedy Algorithm"
fracR(x,n)==
   y:=x;a:L:=[];c:=0;q:=denom x;q:=q^4
   for i in n.. repeat
      (c:=c+1)>50   =>(a:=[];break)
      1/i>y         =>1
      member?(1/i,a)=>1
      a:=concat(a,1/i)
      (y:=y-1/i)=0  =>break
      numer(y)=1 and ~member?(y,a)=>(a:=concat(a,y);break)
      (i:=floor(1/y))>q           =>(a:=[];break)
   a

-- Return one List a=[1/x1,...,1/xn] with xn PI and x=r/s=reduce(+,a) or return [] for fail
Frazione2SommaReciproci(x:FRAC INT):L==
    a:L:=[]
    x>1       =>a
    numer(x)=1=>[x]
    n:=max(2,floor(1/x));xv:=m:=999;d:=denom x;zd:=divisors d;z:=copy zd
    for i in 2..30 repeat z:=concat(z,i*zd)
    d:=min(10*d,n+9*m) 
    for i in n..d repeat
        (c:=maxIndex(b:=fracR(x,i)))=0=>1 
        c>m+1                         =>1
        M(b)
        v:=reduce(+,delete(b,1))
        for j in z repeat
              (c:=1+maxIndex(q:=fracR(v,j)))=1=>1
              member?(b.1,q)                  =>1
              q:=concat(b.1,q)
              M(q) 
    reverse(sort a)

(7) -> [[i,h(i)] for i in [1/23,2/23,43/48,8/11,5/121,2020/2064,6745/7604,77/79,732/733]]
   (7)
      1   1      2   1  1      43  1 1  1      8  1 1  1  1
   [[--,[--]], [--,[--,---]], [--,[-,-,--]], [--,[-,-,--,--]],
     23  23     23  12 276     48  2 3 16     11  2 6 22 66
      5    1  1   1      505  1 1 1  1    1
    [---,[--,---,---]], [---,[-,-,-,---,----]],
     121  33 121 363     516  2 3 7 602 1204
     6745  1 1  1  1    1      1       77  1 1 1  1  1   1
    [----,[-,-,--,---,-----,------]], [--,[-,-,-,--,---,---]],
     7604  2 3 19 950 72238 570300     79  2 3 8 79 474 632
     732  1 1 1  1   1    1     1
    [---,[-,-,-,--,----,-----,-----]]]
     733  2 3 7 45 7330 20524 26388
                                                      Type: List List Any
       Time: 0.07 (IN) + 200.50 (EV) + 0.03 (OT) + 9.28 (GC) = 209.88 sec
(8) -> h(124547787/123456789456123456)
   (8)
        1             1                         1
   [---------, ---------------, ---------------------------------,
    991247326  140441667310032  613970685539400439432280360548704
                                     1
    -------------------------------------------------------------------]
    3855153765004125533560441957890277453240310786542602992016409976384
                                              Type: List Fraction Integer
                     Time: 17.73 (EV) + 0.02 (OT) + 1.08 (GC) = 18.83 sec
(9) -> h(27538/27539)
         1 1 1  1  1    1      1        1
   (9)  [-,-,-,--,---,-----,------,----------]
         2 3 7 52 225 10332 826170 1100871525
                                              Type: List Fraction Integer
                     Time: 0.02 (IN) + 28.08 (EV) + 1.28 (GC) = 29.38 sec

referencia y números de: http://www.maths.surrey.ac.uk/hosted-sites/R.Knott/Fractions/egyptian.html

para agregar algo, este a continuación sería el optimizado para encontrar la fracción de longitud mínima que tiene el denominador máximo menos (y no está optimizado para longitud)

L==>List FRAC INT

-- this would be the "Greedy Algorithm"
fracR(x,n)==
   y:=x;a:L:=[];c:=0;q:=denom x;q:=q^20
   for i in n.. repeat
      (c:=c+1)>1000  =>(a:=[];break)
      1/i>y          =>1
      member?(1/i,a) =>1
      a:=concat(a,1/i)
      (y:=y-1/i)=0  =>break
      numer(y)=1 and ~member?(y,a)=>(a:=concat(a,y);break)
      (i:=floor(1/y))>q           =>(a:=[];break)
   a

-- Return one List a=[1/x1,...,1/xn] with xn PI and x=r/s=reduce(+,a) or return [] for fail
Frazione2SommaReciproci(x:FRAC INT):L==
    a:L:=[]
    x>1       =>a
    numer(x)=1=>[x]
    n:=max(2,floor(1/x));xv:=m:=999;d:=denom x;zd:=divisors d;z:=copy zd; 
    w1:= if d>1.e10 then 1000 else 300; w2:= if d>1.e10 then 1000 else if d>1.e7 then 600 else if d>1.e5 then 500 else if d>1.e3 then 400 else 100;
    for i in 2..w1 repeat(mt:=(i*zd)::List PI;mv:=[yy for yy in mt|yy>=n];z:=sort(removeDuplicates(concat(z,mv)));#z>w2=>break)
    for i in z repeat
        (c:=maxIndex(b:=fracR(x,i)))=0=>1 
        c>m+1                         =>1
        if c<m or(c=m and m<999 and reduce(max,map(denom,b))<xv)then(m:=c;a:=b;xv:=reduce(max,map(denom,a)))
        v:=reduce(+,delete(b,1))
        for j in z repeat
              (c:=1+maxIndex(q:=fracR(v,j)))=1=>1
              member?(b.1,q)                  =>1
              q:=concat(b.1,q)
              if c<m or(c=m and m<999 and reduce(max,map(denom,q))<xv)then(m:=c;a:=q;xv:=reduce(max,map(denom,a)))
    reverse(sort a)

Los resultados:

(5) -> [[i,Frazione2SommaReciproci(i)] for i in [1/23,2/23,43/48,8/11,5/121,2020/2064,6745/7604,77/79,732/733]]
   (5)
      1   1      2   1  1      43  1 1  1      8  1 1  1  1
   [[--,[--]], [--,[--,---]], [--,[-,-,--]], [--,[-,-,--,--]],
     23  23     23  12 276     48  2 3 16     11  2 6 22 66
      5    1  1   1      505  1 1 1  1    1
    [---,[--,---,---]], [---,[-,-,-,---,----]],
     121  33 121 363     516  2 3 7 602 1204
     6745  1 1  1  1    1      1       77  1 1 1  1  1   1
    [----,[-,-,--,---,-----,------]], [--,[-,-,-,--,---,---]],
     7604  2 3 19 950 72238 570300     79  2 3 8 79 474 632
     732  1 1 1  1   1    1     1
    [---,[-,-,-,--,----,-----,-----]]]
     733  2 3 7 45 7330 20524 26388
                                                      Type: List List Any
                     Time: 0.08 (IN) + 53.45 (EV) + 3.03 (GC) = 56.57 sec
(6) -> Frazione2SommaReciproci(124547787/123456789456123456)
   (6)
        1            1               1                  1
   [---------, ------------, ----------------, -------------------,
    994074172  347757767307  2764751529594496  1142210063701888512
                      1
    -------------------------------------]
    2531144929865351036156388364636113408
                                              Type: List Fraction Integer
         Time: 0.15 (IN) + 78.30 (EV) + 0.02 (OT) + 5.28 (GC) = 83.75 sec
(7) -> Frazione2SommaReciproci(27538/27539)
         1 1 1  1   1     1       1       1
   (7)  [-,-,-,--,----,-------,-------,-------]
         2 3 7 43 1935 3717765 5204871 7105062
                                              Type: List Fraction Integer
                     Time: 0.05 (IN) + 45.43 (EV) + 2.42 (GC) = 47.90 sec

Parece que muchos buenos denominadores tienen como divisores de factores del denominador de fracción de entrada.



0

APL (NARS), 2502 bytes

fdn←{1∧÷⍵}⋄fnm←{1∧⍵}⋄ffl←{m←⎕ct⋄⎕ct←0⋄r←⌊⍵⋄⎕ct←m⋄r}⋄divisori←{a[⍋a←{∪×/¨{0=≢⍵:⊂⍬⋄s,(⊂1⌷⍵),¨s←∇1↓⍵}π⍵}⍵]}

r←frRF w;x;y;c;q;i;j
(x i)←w⋄i-←1⋄y←x⋄r←⍬⋄c←0⋄q←fdn x⋄q←q*20
i+←1
→4×⍳∼1000<c+←1⋄→6
j←÷i⋄→2×⍳j>y⋄→2×⍳(⊂j)∊r⋄r←r,(⊂j)⋄y←y-j⋄→0×⍳y=0⋄→5×⍳1≠fnm y⋄→5×⍳(⊂y)∊r⋄r←r,⊂y⋄→0
→2×⍳∼q<i←ffl ÷y
r←⍬

r←fr2SumF x;n;xv;m;d;zd;z;i;b;c;t;v;j;k;q;w1;w2;t;b1
z←r←⍬⋄→0×⍳1≤ffl x
:if 1=fnm x⋄r←,⊂x⋄→0⋄:endif
n←2⌈ffl÷x⋄xv←m←999⋄d←fdn x⋄zd←divisori d
w1←1000⋄w2←50⋄:if d>1.e10⋄w2←700⋄:elseif d>1.e7⋄w2←600⋄:elseif d>1.e5⋄w2←500⋄:elseif d>1.e3⋄w2←400⋄:elseif d>1.e2⋄w2←100⋄:endif
:for i :in ⍳w1⋄z←∪z∪k/⍨{⍵≥n}¨k←i×zd⋄:if w2<≢z⋄:leave⋄:endif⋄:endfor
z←∪z∪zd⋄z←z[⍋z]
:for i :in z
    :if 0=c←≢b←frRF x i ⋄:continue⋄:endif
    :if      c>m+1      ⋄:continue⋄:endif
    :if      c<m        ⋄m←c⋄r←b⋄xv←⌈/fdn¨b
    :elseif (c=m)∧(m<999)
         :if xv>t←⌈/fdn¨b⋄m←c⋄r←b⋄xv←t⋄:endif
    :endif
    :if c≤2⋄:continue⋄:endif
    v←↑+/1↓b⋄b1←(⊂↑b)
    :for j :in z
       :if 1=c←1+≢q←frRF v j⋄:continue⋄:endif
       :if        b1∊q      ⋄:continue⋄:endif
       q←b1,q
       :if  c<m⋄m←c⋄r←q     ⋄xv←⌈/fdn¨q
       :elseif (c=m)∧(m<999)
           :if xv>t←⌈/fdn¨q⋄m←c⋄r←q⋄xv←t⋄:endif
       :endif
    :endfor
:endfor
→0×⍳1≥≢r⋄r←r[⍋fdn¨r]

Traslación del código AXIOM para este problema, a APL, utilizando por primera vez (para mí) el tipo de fracción (que es bignum ...).

103r233 significa la fracción 103/233. Prueba:

  ⎕fmt fr2SumF 1r23
┌1────┐
│ 1r23│
└~────┘
  ⎕fmt fr2SumF 2r23
┌2──────────┐
│ 1r12 1r276│
└~──────────┘
  ⎕fmt fr2SumF 43r48
┌3────────────┐
│ 1r2 1r3 1r16│
└~────────────┘
  fr2SumF 8r11
1r2 1r6 1r22 1r66 
  fr2SumF 5r121
1r33 1r121 1r363 
  fr2SumF 2020r2064
1r2 1r3 1r7 1r602 1r1204 
  fr2SumF 6745r7604
1r2 1r3 1r19 1r950 1r72238 1r570300 
  fr2SumF 77r79
1r2 1r3 1r8 1r79 1r474 1r632 
  fr2SumF 732r733
1r2 1r3 1r7 1r45 1r7330 1r20524 1r26388 
  fr2SumF 27538r27539
1r2 1r3 1r7 1r43 1r1935 1r3717765 1r5204871 1r7105062 
  fr2SumF 124547787r123456789456123456
1r994074172 1r347757767307 1r2764751529594496 1r1142210063701888512 
  1r2531144929865351036156388364636113408 
Al usar nuestro sitio, usted reconoce que ha leído y comprende nuestra Política de Cookies y Política de Privacidad.
Licensed under cc by-sa 3.0 with attribution required.