埃及分数


20

概述:

来自维基百科:埃及分数是不同单位分数的总和。即,表达式中的每个分数都有一个等于1的分子和一个为正整数的分母,并且所有分母彼此不同。这种类型的表达式的值为正有理数a / b。每个正有理数都可以用埃及分数表示。

挑战:

编写最短函数,该函数将返回加总给定分数的最小单位分数的所有分母的值。

规则/约束:

  • 输入将是两个正整数值。
    • 这可以是STDINargv,逗号分隔,空格分隔,或其他任何你喜欢的方法。
  • 第一个输入值应为分子,第二个输入值应为分母。
  • 第一个输入值应小于第二个输入值。
  • 输出的值可能超过系统/语言(RAM,MAX_INT或存在的任何其他代码/系统约束)的内存限制。如果发生这种情况,只需将结果截断为可能的最高值,然后注意(即...)。
  • 输出应该能够处理至少2147483483647(2 31 -1,32 位带符号int)的分母值。
    • 较高的值(long等)完全可以接受。
  • 输出应是找到的最小单位分数集(或分数本身,即1/2)的分母的所有值的列表。
  • 输出应按照分母的值升序排序(以分数的值降序)。
  • 可以使用任何希望的方式对输出进行定界,但是两者之间必须有一些字符,以便将一个值与下一个值区分开。
  • 这就是代码高尔夫,因此最短的解决方案将获胜。

举例:

  • 输入1:

    43, 48

  • 输出1:

    2, 3, 16

  • 输入2:

    8/11

  • 输出2:

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

  • 输入3:

    5 121

  • 输出3:

    33 121 363


输入/输出2应该是8, 112, 6, 22, 66吧?
mellamokb

2
消除歧义的一种可能建议是要求使用最小的分母的最小单位分数集。例如,对于input而言1/2 1/6 1/22 1/66更可取。1/2 1/5 1/37 1/40708/11
primo 2012年

2
我建议增加5/121 = 1/33+1/121+1/363测试用例。所有贪心程序(包括我的贪婪程序)都会给出5个分数。摘自Wikipedia的示例。
ugoren 2012年

1
@primo我认为,如果有多个最小值,那么可以找到的任何一个都是可以接受的。如果可以用更少的字符来编写一种算法,那么我就不会阻碍这种解决方案。
加菲2012年

1
自从我在数学史课程中实际上了解了埃及分数后,就获得了+1(必须与它们进行数学运算,以及找到像这样的分数和)。这是一个很好的,富有创造力的挑战。
mbomb007

Answers:


6

普通Lisp,137个字符

(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)->(25 757 763309 873960180913 1527612795642093418846225)

无需担心庞大的数字或处理分数表示法!


(defun z(n)(labels((i(nsr)(cond((= n 0)r)((<n(/ 1 s))(in(天花板(/ 1 n))r))(t( i(-n(/ 1 s))(1+ s)(cons sr)))))(reverse(in 2'()))))(z 43/48)显示结果不正确我必须使用什么来打印结果?
RosLuP

1
(print(z 103/333))返回一个由5个数字组成的列表,但将存在一个由4个数字组成的列表,如:1 / 4,1 / 18,1 / 333,1 / 1332。因此,上述函数不会返回最小值。
RosLuP

8

Python 2,169167个字符

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

在stdin上使用逗号分隔的args,并在stdout上打印python列表。

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

2
1.我认为您可以通过使用第二个缩进级别上的tab来保存两个字符。2.由于超出系统内存限制,该脚本不指示截断。
面包箱2012年

在Tio中,您的代码仅在103/45533时内存不足
RosLuP

相反,在Ideone中,您的代码在同一输入103,45533中出现运行时错误:运行时错误#stdin #stdout #stderr 0.89s 99264KB
RosLuP

4

PHP 82字节

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

可以使它更短一些,但是当前分子和分母必须保持为整数,以避免浮点舍入误差(而不是保持当前分数)。

用法示例:

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

逗号运算符被模拟为printf的无用参数吗?我应该把这个技巧保存在某个地方。
Konrad Borowski

1
我很确定这是贪婪算法,因此它不会总是给出最小的分数集。如果使用类似5 121或的输入运行它31 311,则会给出错误的答案(经过很长时间)。
grc 2012年

@grc 31/311-> {a [1]-> 11,a [2]-> 115,a [3]-> 13570,a [4]-> 46422970}
belisarius博士2012年

4

C,163177个字符

6/6:最后,该程序现在可以在所有情况下正确处理截断了。花了很多字符,超出了我的期望,但这是值得的。该程序现在应该100%遵守问题要求。

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]);}

该程序在标准输入上使用分子和分母。分母被打印到标准输出,每行一个。截断的输出通过在列表的末尾打印一个零分母来表示:

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

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

第二个示例中的分母加起来为95485142815/107645519046,与6745/7604的差约为1e-14。


同样,我认为这是一个贪婪算法。
grc 2012年

最外面的循环在开始测试N + 1分母的答案之前,先探究N分母的所有可能答案。我想您可以称它为贪婪,但我相信它可以解决上述问题。
面包箱2012年

抱歉,我收回了。它没有遵循贪婪的解决方案,但是我发现对于某些输入(31 311例如),它并不完全准确。
grc 2012年

31 311溢出,但是程序无法对其进行标记。
面包箱2012年

3

Python,61个字符

来自STDIN的输入,以逗号分隔。
输出到STDOUT,换行符分隔。
并不总是返回最短的表示形式(例如5/121)。

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

计算字符时不需要多余的换行符(即,在whileusing中加入所有行;)。
分数是a/b
ib/a四舍五入,所以我知道1/i <= a/b
打印后1/i,我代替a/ba/b - 1/i,这是(a*i-b)/(i*b)


我要投票这件事,因为它如此之小,但它只是缺少一件!
加菲2012年

2
我想修复此问题,但是不会太小……我有一种感觉,我将重新发明Keith Randall的解决方案。
ugoren 2012年

2

C,94个字节

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;}}

在线试用

编辑:注释中张贴了较短版本的代码,因此我将其替换。谢谢!


2
您好,欢迎光临本站!这是一场代码竞赛,所以目标是使您的代码尽可能短。看起来您可以做很多事情来使代码更短。例如,您可以从答案中删除所有不必要的空格。
DJMcMayhem

@DJMcMayhem先生,谢谢您,理解并完成。
うちわ密か2017年

嗨,欢迎来到PPCG!您能否为挑战中的测试用例添加带有测试代码的TryItOnline链接?此外,有些事情你可以打高尔夫球:for(i=2;n>0&&i>0;i++)可以for(i=1;n>0&++i>0;); 可以移除for循环的括号(因为它只有if内部);d=d*i;可以d*=i;; 并且我不确定,但我认为#include <stdio.h>可以没有空格:#include<stdio.h>。哦,阅读C 语言打高尔夫球的技巧
Kevin Cruijssen 17-10-26

@KevinCruijssen感谢您的提示。
うちわ密か2017年



0

AXIOM,753字节

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))

这个想法将应用带有不同初始点的“贪心算法”,并保存长度最小的列表。但并非总是如此,它会找到定义不那么严格的最小解:“当且仅当A的元素数少于B或A的元素数与B的元素数相同时,A数组才会小于B数组。 ,如果A的较小元素的个数大于B的较小元素,则比A小于B。取消测试

-- 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

参考和编号来自: http //www.maths.surrey.ac.uk/hosted-sites/R.Knott/Fractions/egyptian.html

为了增加一些东西,下面将是为查找最小长度分数而优化的那个,它的最大分母较少(并且没有针对长度进行优化)

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)

结果:

(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

似乎许多好的分母具有输入分数分母的因子除数。



0

APL(NARS),2502字节

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]

从这个问题的AXIOM代码到APL的转换,对我来说是第一次使用分数类型(即bignum ...)。

103r233表示分数103/233。测试:

  ⎕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 
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.