数平方


18

挑战

折纸(折纸)是一种创造性的艺术形式。据我所知,折纸大师更喜欢方形纸。让我们从头开始-将矩形纸转换为正方形纸。

因此,纸张分为正方形。我们逐步删除与当前形状共有一个较短边的最大正方形(请参见下图)。并且,如果一步之后的剩余部分小于或等于0.001 * (area of the original paper),则无法进一步分割纸张。最后可能什么也没剩下。

您的任务是计算在此过程中制作了多少个正方形。使纸张无法分割的最后一步的平方计入输出。

示例(1.350宽度/高度的纸张),输出为10:

切片示例

输入输出

输入:矩形纸的宽度/高度比,从1.002到的十进制数(或不带点的整数),1.999最小步长为0.001。您也可以使用任何其他合理的格式来描述比率。只需在您的答案中提及它即可。

输出:平方数,一个整数。

示例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个十进制数字的精度,这在中进行了介绍float


可以将构成比例的两个数字用作输入吗?
路易斯·门多

@LuisMendo是的,如您所愿。
Keyu Gan

2
整齐的挑战!
瑕疵

5
答案列表产生了一个漂亮的图表
Luis Mendo'1

1
@KeyuGan当然,继续!让我知道您是否需要其他格式的版本
Luis Mendo

Answers:


2

MATL,19字节

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

输入是一个数组,其中两个数字定义了原始比率,例如[1, 1.009]。(没有必要对数字进行排序或其中之一为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好主意,谢谢!
瑕疵

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真的很整洁!!!
瑕疵

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]return 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。

通常,在欧几里得算法中,人们会跟踪这些中间维度,并丢弃减法数;但是,可以交替记录我们在差值变得太小之前从另一个数中减去一个数的次数,而我们必须切换要减去的数。该记录方法恰好是有理数的连续分数。(连续的无理数分数永远不会终止,也很酷,但在这里不相关。)例如,在示例1350/1000中,我们先减去1000 1次,再减去350 2次,再减去300次,再减去150 6次。因此1350/1000的继续分数是{1,2,1,6}。数学上,我们将1350/1000改写为1+ 1 /(2+ 1 /(1+ 1 /6)),您可以进行验证。

因此,对于这个问题,如果您不停止平方数小于某个阈值的情况,而只是在停止之前数所有有限的平方数,那么平方总数等于减法的总数,也就是说连续分数中所有整数的总和,而这正是函数组成所Tr@*ContinuedFraction计算的!(对于给定的示例1.35,它得到了OP期望的答案,因为最终的正方形足够大,可以计算所有正方形。但是Tr@*ContinuedFraction[1001/1000],例如,yields 1001,因为它可以计算一个大正方形和所有1000个小1x1000正方形)


1
尽管这确实很有趣,但是非竞争标签保留用于比挑战更新的语言。与此无关,所有答案的确需要解决挑战。因此,该答案应真正删除。您是否可以从连续分数列表中重构出要在哪里截断的方法,以便可以将其转化为同样有趣但有效的解决方案?
Martin Ender

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

输入是两个不带点的整数(宽度和高度),例如f(1999,1000)

我希望有人可以节省一个字节,将C推入58字节的俱乐部。;)


建议删除括号周围m-=n
ceilingcat

1

C,59个字节

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

在线试用

输入是一个整数,它是宽度/高度比(以千分之一为单位)(例如,对于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;
}
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.