正方形を数える


18

チャレンジ

折り紙(折り紙)は芸術の創造的な形式です。私の知る限り、折り紙の達人は正方形の紙を好みます。最初から始めましょう-長方形の紙を正方形の紙に変換します。

したがって、紙は正方形に分割されます。現在の形状と1つの短いエッジを共有する最大の正方形を段階的に削除します(下の図を参照)。また、1ステップ後の残りの部分がより小さいか等しい場合0.001 * (area of the original paper)、用紙はそれ以上分割できません。最後に何も残っていない可能性があります。

あなたのタスクは、プロセス中に作成される正方形の数を計算することです。用紙を分割できない最後のステップの正方形は、出力にカウントされます。

例(1.350幅/高さの用紙)、出力は10です:

スライスの例

入出力

入力:長方形の紙の幅/高さの比、1桁の小数(またはドットのない整数)から1.002まで1.999、最小ステップ0.001。また、比率を説明する他の合理的な形式を使用することもできます。答えにそれを記載してください。

出力:平方カウント、1つの整数。

I / Oの例

コードはリスト入力をサポートしたり、マッピング関数である必要はありませんが、ページを整理するためにマッピング形式が使用されます。

1.002 => 251
1.003 => 223
1.004 => 189
1.005 => 161
1.006 => 140
1.007 => 124
1.008 => 111
1.009 => 100

すべての回答のリスト

@LuisMendoのおかげで、ここに回答のグラフがあります。

グラフ

備考

  • これはコードゴルフなので、最短のコードが勝ちます
  • 標準的な抜け穴に注意する
  • 入力と出力の処理方法を決めるのはあなたの自由ですが、標準の制限に従う必要があります。

ところで...

  • 課題について不明な点がある場合はコメントしてください
  • 個人的には、ゴルフの言語を使用している場合は、答えに説明を含めることをお勧めします
  • @GregMartinのおかげで、このチャレンジの数学的な説明については彼の答えを読んでください。

サンプルコード

以下は、C ++コードの未使用バージョンです。

#include <iostream>
#include <utility>

int f (double m)
{
    double n = 1, k = 0.001;
    int cnt = 0;
    k *= m;                       // the target minimum size
    while(m*n >= k)
    {
        m -= n;                   // extract a square
        if(n > m)
            std::swap(n, m);      // keep m > n
        ++ cnt;
    }
    return cnt;
}

int main()
{
    double p;
    std::cin >> p;
    std::cout << f(p);
    return 0;
}

サンプルコードに関連するすべての計算には、6桁の10進数の精度が必要floatです。


比率を形成する2つの数値を入力として使用できますか?
ルイスメンドー

@LuisMendoはい、あなたの願いとして。
キーガン

2
きちんとした挑戦!
-flawr


1
@KeyuGanもちろん、どうぞ!あなたには、いくつかの他の形式のバージョンが必要な場合は、私に教えてください
ルイスMendo

回答:


2

MATL、19バイト

`SZ}y-htG/p1e-3>}x@

入力は、などの元の比率を定義する2つの数値を持つ配列[1, 1.009]です。(番号を並べ替えたり、1つを1にする必要はありません。)

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

説明

`        % Do...while loop
  S      %   Sort array. Takes 1×2 array as input (implicit) the first time
  Z}     %   Split array into its 2 elements: first the minimum m, then the maximum M
  y      %   Duplicate m onto the top of the stack. The stack now contains m, M, m
  -      %   Subtract. The stack now contains m, M-m
  h      %   Concatenate into [m, M-m]. This is the remaining piece of paper
  t      %   Duplicate
  G/     %   Divide by input, element-wise
  p      %   Product of array. Gives ratio of current piece's area to initial area
  1e-3>  %   True if this ratio exceeds 1e-3. In that case the loop continues
}        % Finally (execute after last iteration, but still within the loop)
  x      %   Delete last piece of paper
  @      %   Push current loop counter. This is the result
         % End (implicit)
         % Display (implicit)

6

Haskell71 70 65 63 62 61 58 56バイト

いくつかの巧妙な改善をしてくれた@xnorに感謝します!

(n#m)e|e>n*m*1e3=0|n<m=m#n$e|d<-n-m=(d#m)e+1
n!m=n#m$n*m

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


m==n最後にできるのは1>0、それが唯一の可能性だからだと考えています。または、ここでバインドできるようにケースを再配置できます。
-xnor

実際には、平等のケースが必要ですか?場合n>mに拡張するn>=mと、最初のチェックが書き込まれe>m*n*1000、それが与えるべき1平等のために。
-xnor

@xnor良いアイデア、ありがとう!
-flawr

1
56の警備員の移動:(n#m)e|e>n*m*1e3=0|n<m=m#n$e|d<-n-m=(d#m)e+1;n!m=n#m$n*m
xnor

うわー、d<-n-masの使用otherwiseは本当にすてきです!!!
-flawr

4

JavaScript(ES6)、59 58バイト

f=(m,n=!(k=m/1e3,c=0))=>m*n<k?c:(c++,m-=n)<n?f(n,m):f(m,n)

テスト


4

Mathematica、非競合(21バイト)

この回答は、実際の質問に答えないため、競合しません。しかし、それは質問の変形に答えて、いくつかの興味深い数学を強調する口実を提供します。

Tr@*ContinuedFraction

入力として正の有理数(分子と分母は元の紙の次元を表す)を取り、正の整数を返すシンボリック関数。たとえば、をTr@*ContinuedFraction[1350/1000]返します10。(ContinuedFraction精度の問題により、浮動小数点数に対して異なる動作をします。このため、このコンテキストでは入力として有理数が必要です。)

問題で説明されている幾何学的手順の興味深い解釈(繰り返し四角形から四角形を切り取る)は、最大公約数を見つけるためのユークリッドアルゴリズムの実装です!比率で、質問自体の例を検討してください1.35、寸法(1350,1000)の紙を使用してモデル化できます。正方形が切り取られるたびに、大きい数値から小さい数値が差し引かれます。したがって、この例の結果の長方形の寸法は(350,1000)、(350,650)、(350,300)、(50,300)、(50,250)および(50,200)および(50,150)および(50,100)および(50、 50)、および(50,0)から最後の正方形を取り去ります。これはまさに、ユークリッドアルゴリズムの動作(除算と反復減算の差を調整)であり、実際、50は1350と1000のGCDであることがわかります。

通常、ユークリッドアルゴリズムでは、これらの中間次元を追跡し、減算の数を破棄します。ただし、1つの数値をもう1つの数値から何回減算したかを記録して、差が小さくなりすぎて、減算する値を切り替える必要があります。記録のその方法は、正確に有理数の連続した部分です。(終了しない無理数の連続した部分も超クールですが、ここでは関係ありません。)たとえば、例1350/1000では、1000 1回、350 2回、300 1回、50 6回の減算を行いました。したがって、1350/1000の継続分数はです{1,2,1,6}。数学的には、1350 1/ 1000を+ 1 /(2+ 1 /(1+ 1 /6))、確認できます。

したがって、この問題では、正方形が特定のしきい値より小さくなったときに停止せず、停止する前に単純に有限数の正方形をすべてカウントすると、正方形の合計数は減算の合計数に等しくなります連続した小数部のすべての整数の合計。これが、関数の構成がTr@*ContinuedFraction計算するものです。(与えられた例1.35の場合、最終的な正方形はすべての正方形を数えるのに十分な大きさであるため、OPが望む答えを取得します。しかしTr@*ContinuedFraction[1001/1000]、例えば、10011つの巨大な正方形と小さな1x1000 )


1
これは確かにおもしろいですが、非競合ラベルはチャレンジより新しい言語のために予約されています。それとは別に、すべての答えは課題を解決する必要があります。したがって、この回答は実際に削除する必要があります。これを同様に興味深いが、有効な解決策に変えることができるように、どこでそれを切り捨てるかを継続分数リストから再構築することができますか?
マーティンエンダー

1
私はこの答えを書くときにひっかきたいという精神的な悩みを抱えていましたが、これはコミュニティの基準では削除に値する答えであることに同意します。(丁寧で正確なフィードバックをありがとう!)TPTBが削除を24時間遅らせたいと思うなら、正しい答えを得るためのアプローチを複雑化できるかもしれません...そうでなければ、削除し、苦痛を感じません。
グレッグマーティン

3

Mathematica、64 53バイト

({t=1,#}//.{a_,b_}/;1000a*b>#:>Sort@{++t;a,b-a};t-1)&

命令型(Cスタイル)のソリューションは、まったく同じ長さです。

(For[t=a=1;b=#,1000a*b>#,If[a>b,a-=b,b-=a];++t];t-1)&

2

C(GCC / Clang)、 61 59バイト

c,k;f(m,n){for(k=m*n;m*n/k;m>n?(m-=n):(n-=m))++c;return c;}

入力は、などのドットなしの2つの整数(幅と高さ)f(1999,1000)です。

Cを58バイトのクラブにプッシュする1バイトを誰かが節約できることを願っています。;)


括弧を削除することをm-=n
提案し

1

C、59バイト

s,a,n=1e3;C(m){for(a=m;m*n>a;s++)m>n?m-=n:(n-=m);return s;}

オンラインで試す

入力は、1000分の1単位の幅/高さの比率である整数です(たとえば、1.002:1の場合は1002)。

ゴルフされていないバージョン

int C(int m)
{
    int n = 1000;
    int a = m;
    int s = 0;

    while (m * n > a)
    {
        if (m > n)
            m -= n;
        else
            n -= m;

        s++;
    }

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