エジプト分数


20

概要:

ウィキペディアから:エジプトの分数は、異なる単位分数の合計です。つまり、式の各分数には1に等しい分子と正の整数である分母があり、すべての分母は互いに異なります。このタイプの式の値は、正の有理数a / bです。すべての正の有理数は、エジプトの分数で表すことができます。

チャレンジ:

特定の分数に達する単位分数の最小セットのすべての分母の値を返す最短関数を記述します。

ルール/制約:

  • 入力は2つの正の整数値になります。
    • これは、上ですることができSTDINargv、カンマ区切り、スペースが区切られ、あるいは他の方法は、あなたが好みます。
  • 最初の入力値は分子で、2番目の入力値は分母です。
  • 最初の入力値は2番目の入力値よりも小さくなければなりません。
  • 出力には、システム/言語のメモリ制限(RAM、MAX_INT、またはその他のコード/システム制約が存在する)を超える値が含まれる場合があります。これが発生した場合は、できるだけ高い値で結果を切り捨てて、何らかの形で(つまり...)に注意してください。
  • 出力は、少なくとも2,147,483,647(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
あいまいさを取り除くための可能な提案は、最小の最終分母を持つ最小の単位分数のセットを要求することです。たとえば、入力には1/2 1/6 1/22 1/66望ましいでしょう。1/2 1/5 1/37 1/40708/11
プリモ

2
5/121 = 1/33+1/121+1/363テストケースに追加することをお勧めします。すべての貪欲なプログラム(私のものを含む)は5つの分数を与えます。ウィキペディアからの例。
ウゴレン

1
@primo最小値が複数ある場合、どちらかが見つかったとしても許容できると思います。その結果、1つのアルゴリズムでより少ない文字数で記述できる場合、その解決策を妨げたくありません。
ガフィ

1
数学の歴史のコースでエジプトの分数について実際に学んだので、+ 1を与えました(そして、それらを使って数学を行い、この問題のような小数の合計を見つける必要がありました)。素敵で創造的な挑戦。
mbomb007

回答:


6

Common 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(ceiling(/ 1 n))r))(t( i(-n(/ 1 s))(1+ s)(cons sr))))))(reverse(in 2 '())))))(z 43/48)結果がtioにならない...結果を印刷するには何を使用する必要がありますか?
RosLuP

1
(print(z 103/333))5つの数字のリストを1つ返しますが、4つの数字のリストは1 / 4、1 / 18、1 / 333、1 / 1332として存在します。したがって、上記の関数は最小値を返しません。
RosLuP

8

Python 2、169 167文字

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でコンマ区切りの引数を取り、stdoutにPythonリストを出力します。

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

2
1. 2番目のインデントレベルでタブを使用して2つの文字を保存できると思います。2.スクリプトは、システムメモリの制限を超えているため、切り捨てを示しません。
ブレッドボックス

In 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への無駄な引数としてエミュレートされていますか?このトリックをどこかに保存する必要があります。
コンラッドボロウスキ

1
私はこれが貪欲なアルゴリズムであると確信しているので、常に分数の最小セットを与えるとは限りません。5 121または31 311などの入力で実行すると、(非常に長い時間の後)間違った答えが返されます。
GRC

@grc 31/311-> {a [1]-> 11、a [2]-> 115、a [3]-> 13570、a [4]-> 46422970}
ベリサリウス博士

4

C、163 177文字

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

プログラムは、標準入力で分子と分母を取ります。分母は標準出力に1行に1つずつ出力されます。切り捨てられた出力は、リストの最後にゼロ分母を出力することで示されます。

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

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

2番目の例の分母の合計は95485142815/107645519046であり、これは6745/7604と約1e-14異なります。


繰り返しますが、これは貪欲なアルゴリズムだと思います。
GRC

最も外側のループは、N + 1分母の回答のテストを開始する前に、N分母のすべての可能な回答を調査します。あなたはそれを貪欲と呼ぶことができますが、私はそれが述べられた問題を満たしていると信じています。
パンボックス

申し訳ありませんが、私はそれを取り戻します。貪欲な解決策には従いませんが、一部の入力(31 311たとえば)に対して完全に正確ではないことがわかりました。
GRC

31 311オーバーフローしますが、プログラムはフラグを立てません。
ブレッドボックス

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)


これ非常に小さいので投票したいのですが、その1つが欠けているだけです!
ガフィ

2
これを修正したいのですが、それほど小さくはありません...キースランドールのソリューションを再発明したい気がします。
ウゴレン

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ありがとうございます。
うちわ密か

こんにちは、PPCGへようこそ!チャレンジ内のテストケースのテストコードを含むTryItOnline-linkを追加できますか?また、あなたがゴルフ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でのゴルフのためのヒント<すべての言語>でゴルフのためのヒント
ケビンCruijssen

@KevinCruijssenヒントをありがとう。
うちわ密か'10



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よりも、Aのより小さな要素が数値として大きい場合、Bのより小さな要素よりも小さい場合、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

C、85 78バイト

@ceilingcatによって改善された78バイト:

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

オンラインでお試しください!


私の元の答え、85バイト:

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

オンラインでお試しください!

クレジットの一部は、私が改良したこの 94バイトのソリューションを書いたJonathan Frechに送られるべきです。


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コードから、初めて(私にとっては)分数型(bignum ...)を使用したAPLへの変換。

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 
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.