原始勾股三元组


29

相关

毕达哥拉斯三重是一个列表(a, b, c),其满足等式一个2 + B 2 = C 2

原始毕达哥拉斯三(PPT)为其中abc是全部互质(即,三个元件之间的唯一的公约数是1)。例如,(3, 4, 5)直角三角形是著名的原始毕达哥拉斯三重奏。

挑战

  • 给定输入n,输出n第PPT张。要么,
  • 给定输入n,输出第一个nPPT。

有多种方法可以对这些PPT进行排序,以形成排列良好的列表,从而确定哪个是n第一个。您可以选择所需的任何顺序,只要您可以证明(非正式地)算法可以生成所有可能的唯一PPT。例如,您的代码不应同时输出两者,(3,4,5)并且(4,3,5)由于它们是同一三元组的重复,请不要同时输出。

同样,只要声明使用的是代码,代码是零索引还是单索引都是可以的。

例子

在下面的示例中,我使用单索引,输出nth PPT,然后按最小c,然后最小a,然后最小的顺序进行排序b

n | output
1 | (3, 4, 5)
2 | (5, 12, 13)
5 | (20, 21, 29)
12| (48, 55, 73)

规则

  • 输入和输出可以任何方便的格式给出。
  • 在您提交的文件中,请说明您的条目是如何排序的,以及您的条目是0索引还是1索引。
  • 您选择的订单无法创建重复项。
  • 完整的程序或功能都是可以接受的。如果是函数,则可以返回输出而不是打印输出。
  • 如果可能,请提供一个在线测试环境的链接,以便其他人可以尝试您的代码!
  • 禁止出现标准漏洞
  • 这是因此所有常见的高​​尔夫规则都适用,并且最短的代码(以字节为单位)获胜。


2
A103606
英里

我们必须支持的最高投入是多少?我们是否可以假定它适合我们选择的语言的功能?
Xcoder先生17年

1
@ Mr.Xcoder是; 这是一个标准的安全假设,除非您使用它来利用漏洞(例如,该语言仅支持1位数字)以使问题变得微不足道。
AdmBorkBork

2
我找到了我的问题的答案:a和b必须是互质的,这已经足够了proofwiki.org/wiki/…–
edc65

Answers:


12

果冻27 25字节

2字节感谢Jonathan Allan。

²IH;Pµ;ÆḊ
+2ḶḤ‘Œcg/ÐṂÇ€Ṣḣ

在线尝试!

输出第一个n1索引的三元组[b, a, c],按升序排列b,然后按排序a

使用Wikipedia的算法:

a = mn, b = (m² - n²) / 2, c = (m² + n²) / 2

这将为奇数整数的所有唯一共质数对生成所有原始三元组m > n > 0

说明

+2ḶḤ‘Œcg/ÐṂÇ€Ṣḣ    Main link. Argument: n
+2                   Add 2 to n, to get enough results.
  Ḷ                  Get integers [0, 1, ..., n+1].
   Ḥ                 Double to get [0, 2, ..., 2n+2].
    ‘                Increment to get [1, 3, ..., 2n+3].
     Œc              Get all ordered pairs [[1, 3], [1, 5], ..., [2n+1, 2n+3]].
       g/            GCD of each pair.
         ÐṂ          Grab the pairs with minimal GCD (which is 1).
           ǀ        Call the helper link on each pair to get the triples.
             Ṣ       Sort the triples first by a, then by b, then by c.
              ḣ      Get the last n.

²IH;Pµ;ÆḊ    Helper link. Argument: pair [m, n]
²              Square to get [m², n²].
 I             Increments: get [m²-n²].
  H            Halve: get [(m²-n²)/2], i.e. [b].
    P          Product: get mn, i.e. a.
   ;           Append to get [b, a].
     µ         Begin a new monadic chain with argument [b, a].
       ÆḊ      Get the length of the vector, i.e. c.
      ;        Append to get [b, a, c].

这是一个非常好的解释。谢谢!
AdmBorkBork

g/Ị$Ðf-> g/ÐṂ保存两个字节(因为最小gcd为1,并且总是会有至少一个这样的条目)。
乔纳森·艾伦,

另一字节也可以通过替换被保存(虽然使其效率较低)+2ḶḤ‘Œc²Rm2Œc-废料,它为的输入不会工作1:(
乔纳森艾伦

@JonathanAllan感谢您的下注。我确实尝试了很多2字节范围,但不幸的是没有一个足够大。(²ḶḤ‘Œc是我想到的第一个。)
PurkkaKoodari

8

MATL,36字节

`@:Ut&+wmR&fZd1Mhw/vXutnGE<]GY)t&2|h

输入基于1。输出顺序保证每个三元组仅出现一次。顺序说明如下。要进行解释,需要深入研究该程序的工作方式。

该代码k从开始一直在循环增加计数器1。对于每一个k它产生的所有对a = 1,...,kb = 1,...,ka < b,并挑选那些给毕达哥拉斯三重带c <= k。按升序获得对b,然后a

然后,每对均除以其gcd。生成的(可能重复的)对安排为两列矩阵。该矩阵与类似的矩阵垂直连接,该矩阵包含从的较小值获得的累加结果k。然后稳定地对矩阵的行进行重复数据删除。这将删除两种类型的重复项:

  1. 对当前已发现不止一次的货币对k(例如3,4,也由6,8除以其gcd产生的对);

  2. 已发现较小的一对k

实际上,每次迭代k都会找到先前迭代已经找到的所有对。但是它可能会发现它们的顺序不同。例如,k=25将找到三元组7,24,25而不是20,21,29(因为c不能超过k)。稍后,迭代k=29将找到这两者,但是在20,21,29 之前 7,24,25(顺序为b,然后为a)。这就是为什么,k我们不将找到的所有对保留为最新,而是将它们附加到先前的对中并稳定地进行重复数据删除。这样做可以确保任何输入的顺序都相同n

以上内容保证了每个原始勾股三元组最终都会出现,并且只会出现一次。对于输入nk当至少n获得了有效的三元组时,循环结束。然后是第三n个三元组。

在线尝试!

或使用修改后的代码查看n前三部分:

`@:Ut&+wmR&fZd1Mhw/vXutnGE<]G:Y)tU&2sX^h

在线尝试!


1
很好的解释。
AdmBorkBork


5

果冻19 18字节

*g/²_/
4*œc3UṢÇÐḟḣ

该程序采用基于1的索引n并按字典顺序打印前n个 PPT [c,b,a]

这是一个O(64 n解决方案,因此TIO会在输入4和更高电平上扼流。我将努力使其更快。

在线尝试!

替代版本O(n 3),可能有效

为了找到Ñ 三元组- [C Ñ,B Ñ,一个Ñ ] -上面的解决方案假定Ç Ñ ≤4 Ñ,这是很容易验证。然而,A020882证明Ç Ñ〜2πN,所以有ķ使得Ç Ñ ≤KN所有Ñ

如果我们可以取k = 7,则下面的解也是有效的(而且快得多)。

*g/²_/
×7œc3UṢÇÐḟḣ

在线尝试!

怎么运行的

4*œc3UṢÇÐḟḣ  Main link. Argument: n

4*           Compute 4**n, the n-th power of 4.
  œc3        Take all 3-combinations of the set {1, ..., 4**n}, each sorted in
             ascending order. The triples themselves are sorted lexicographically.
     U       Upend; reverse each triple [a, b, c], yielding [c, b, a].
      Ṣ      Sort the descending triples lexicographically. This ensures that their
             order is independent of n.
       ÇÐḟ   Keep only triples for which the helper link returns a falsy value.
          ḣ  Dyadic head; take the first n triples.


*g/²_/       Helper link. Argument: [c, b, a]

 g/          Reduce [c, b, a] by greatest common divisor, yielding g.
*            Elevate the integers to that power, computing [c**g, b**g, a**g].
   ²         Square, yielding [c**2g, b**2g, a**2g].
    _/       Reduce by subtraction, yielding c**2g - b**2g - a**2g.
             Fermat's Last Theorem assures that this difference will be non-zero
             whenever g > 1, so this yields 0 iff g = 1 and c² = a² = b².

4

的JavaScript(ES7),106个 105 103字节

输出第N个PPT。结果以1为索引,并按b的值排序。

n=>(g=(a,b)=>b?g(b,a%b):a,F=a=>(x=a*a+b*b,c=x**.5|0)*c-x*g(a,g(b,c))||--n?F(a-b?a+1:!++b):[a,b,c])(b=1)

演示版


4

MATL,63字节

3lvi:"t"[HlHllO;aOlOHl]!@Y*2eh]]!XuGY)&*tt[lO;Oa]*ssD2)ED2Xy*ss

在线尝试!

打高尔夫球的教训非常错误。无论如何,我都会发布它,因为我想知道是否有更好的高尔夫方法。

我基于此对这个与欧氏公式组合维基百科页面,建设性地生成所有的三倍,而不是尝试和错误方法。

首先,将奇数互质对生成为三叉树。这是通过大矩阵乘法完成的,占了大多数字节数。然后,可以以非常浪费字节的方式应用Euclid公式。如果有人对这两个部分有提示,我很想听听它们。

请注意,为了节省字节数,该程序会生成与输入相同深度的树,而不是log3(n)。此外,会为树的每一行而不是仅为树的最后一行生成子项,然后使用再次过滤Xu。一个有效的建设性方法就这么多。

3lv % Push root node of ternary tree
i:" % Generate a tree of depth of input (WAY too large, but golfy)
t"  % loop over all nodes (golfier than looping over last tree row)
[HlHllO;aOlOHl]! % Matrix to generate three children of current node
@Y* % Multiply with current node to get children
2e  % Reshape to get node pairs
h]] % Append to tree, exit loops
!Xu % Remove duplicates (more efficient to do it before last ] but golfier this way)
GY) % Select n-th odd coprime pair
&*tt % Multiply with it's own transpose to get [m²,m*n;m*n,n²]
[lO;Oa]*ssD % Sum of matrix multiplication = m²-n² to get a
2)ED % Second element doubled for b=2mn
2Xy*ss % Sum of matrix multiplication with identify matrix to get c=m²+n²

3

Haskell,65个字节

([(a,b,c)|c<-[5..],b<-[1..c],gcd c b<2,a<-[1..b],a^2+b^2==c^2]!!)

基于0的索引。对于给定的cb跑到cab,所以c > b > a一直持有。

在线尝试!


3

Python, 67 50 48 46字节

使用维基百科上的公式,

a=m*n, b=(m^2-n^2)/2, c=(m^2+n^2)/2

where m>n>0mand n是互素数和奇数。这是代码

lambda n:[3+2*n,~-(3+2*n)**2-1/2,-~(3+2*n)**2/2]

-17个字节感谢@Martin Ender

在线尝试

通过n使方程式中变量的值始终为1来工作,这意味着m简单地是任何其他奇数值,在这种情况下,3+2*n其中n是原始毕达哥拉斯三元组的数目。这使我们对所有n值都假设值为1 。


欢迎来到PPCG!未命名的函数很好,因此您无需将lambda分配给a(如果这样做,则可以摆脱那里的两个空格)。我也不确定为什么会print在那里,您可以从lambda本身返回值。
马丁·恩德

“您可以证明(非正式地很好)您的算法可以生成所有可能的唯一PPT”。但是此方法仅生成斜边比腿长1的斜边。例如,它从不生成8,15,17。
罗西F

2

外壳,18个字节

↑üOf§=F⌋ȯ¬Ḟ-m□ΠR3N

在线尝试!

-4个字节感谢Zgarb,丹尼斯的启发

超慢速蛮力方法,不适用于大于1的输入的TIO。您可以尝试更易于管理的版本,此处的 a,b≤200

说明

↑üOf§=F⌋ȯ¬Ḟ-m□ΠR3N
              ΠR3N   Get all triples of natural numbers
   f                 Keep only those triples where
      F⌋                their GCD
    §=                  is equal to
        ȯ¬Ḟ-m□          the logical negation of c²-b²-a²
 üO                  Remove duplicates by their sorted version
↑                    Get the first <input> values of this sequence

通过将映射和过滤器组合起来需要20个字节,甚至更慢。
Zgarb

@Zgarb谢谢!我设法打了一个额外的字节:)
Leo

丹尼斯(Dennis)的果冻答案中有18字节的减法。
Zgarb

@Zgarb真好!尽管我有一个疑问:是否可以有两个相同的三元组c?在这种情况下,此解决方案将需要修复
-Leo

嗯,实际上有很多相同的三元组c。无论如何,此18字节的解决方案(使用丹尼斯的另一个技巧)都可以工作。
Zgarb

1

Mathematica,89个字节

使用由c排序的求解

SortBy[{a,b,c}/.Solve[a^2+b^2==c^2&&GCD[a,b]==1&&0<a<b<c<9#,{a,b,c},Integers],Last][[#]]&

Mathematica,124个字节

(s={};Table[If[IntegerQ[c=Sqrt[a^2+b^2]]&&GCD[a,b]==1,AppendTo[s,{a,b,c}]],{a,9#},{b,9#}];SortBy[Union[Sort/@s],Last][[#]])&

1

R(+个数字),88字节

n=scan();while(all(nrow(T)<n))T=numbers::pythagorean_triples(5,5+(F<-F+1));T[n,3:5]

对于使用内置函数生成数字,实际上需要令人惊讶的字节数才能得到我们想要的。内建函数接受两个参数c1c2,并返回具有的三元组c >= c1 & c <= c2。这使到达第三n个三联体有点烦人。这将一次只增加c21,直到输出足够多的行。


1

PHP,273字节

function t($n){$x=[];for($c=3;;$c++)for($b=2;$b<$c;$b++)for($a=2;$a<$b;$a++)if(d($a,$b,$c)&&$a**2+$b**2==$c**2){$x[]=[$a,$b,$c];if(--$n==0)return $x;}}function d($a,$b,$c){for($i=2;$i<$a;$i++)if($a%$i==0&&$b%$i==0||$a%$i==0&&$c%$i==0||$b%$i==0&&$c%$i==0)return 0;return 1;}
  • t($n) 返回具有顺序的[a,b,c]数组 a < b < c
  • 返回从零开始的索引

在线尝试!(那里的代码也是可读的)


1

C,158字节

我相信这是我第一次在这里提交,因此您很可能可以做得更好。

#include<stdio.h>
void f(n){int i=0,j=3,k,l;while(1){for(k=1;k<j;k++){for(l=k;l<j;l++){if(j*j==k*k+l*l)i++;if(i==n){printf("%d %d %d",j,k,l);return;}}}j++;};}

和非高尔夫版本:

#include <stdio.h>

void f(n)
{
  int i=0, j=3, k, l;
  while (1) {
    for (k=1; k<j; k++) {
      for (l=k; l<j; l++) {
        if (j*j==k*k+l*l)
          i++;
        if (i==n) {
          printf("%d %d %d\n", j, k, l);
          return;
        }
      }
    }
    j++;
  };
}

void main()
{
  int i;

  scanf("%d", &i);

  f(i);
  printf("\n");
}

对于a 2 + b 2 = c 2,顺序是c增大,然后a增大。

在该算法中,没有至少b的 两倍的PPT 。


欢迎来到PPCG!
JAD

1

果冻27 25字节

⁽0(ḃs
Ɠḃd2Ḥ’×€Ç
3r5DṭÇæ×/

这是@AndersKaseorg的Haskell答案中树方法的实现,具有不同的分支顺序。该程序使用基于0的索引,并从STDIN获取输入。

在线尝试!

背景

如Wikipedia页面上的原始勾股三叉树的树中所述,每个PPT可以通过将行向量(3,4,5)反复左乘以具有某些属性的矩阵来获得。

在每次迭代中,可以将先前的结果与ABC左乘,可以如下选择。

矩阵

ABC固定时,可以以唯一的方式获得每个PPT。

怎么运行的

3r5DṭÇæ×/  Main link. No arguments.

3          Set the argument and the return value to 3.
 r5        Create a range from 3 to 5, i.e., [3, 4, 5].
   D       Decimal; convert each integer to base 10, yielding [[3], [4], [5]].
     Ç     Call the second helper link with argument 3.
    ṭ      Tack; append [[3], [4], [5]] to the result.
      æ×/  Reduce by matrix multiplication.
Ɠḃd2Ḥ’×€Ç  Second helper link. Argument: 3

Ɠ          Read and evaluate one line of input, yielding an integer n.
 ḃ         Convert n to bijective base 3.
  d2       Divmod 2; map each digit d to [d/2, d%2].
    Ḥ      Unhalve; multiply the results by 2.
     ’     Decrement the doubled results.
           The previous four atoms apply the following mapping to the digits.
               1 -> [0, 1] -> [0, 2] -> [-1,  1]
               2 -> [1, 0] -> [2, 0] -> [ 1, -1]
               3 -> [1, 1] -> [2, 2] -> [ 1,  1]
        Ç  Call the helper link with argument 3, yielding the following 2D array.
               [[ 1,  2,  2],
                [ 2,  1,  2],
                [ 2,  2,  3]]
      ×€   Multiply each [-1,  1], [ 1, -1], and [ 1,  1] by that matrix, using
           vectorizing multiplication (not matrix multiplication), yielding one 
           of the following three 2D arrays.

               [[-1,  2,  2],    [[ 1, -2,  2],    [[ 1,  2,  2],
                [-2,  1,  2],     [ 2, -1,  2],     [ 2,  1,  2],
                [-2,  2,  3]]     [ 2, -2,  3]]     [ 2,  2,  3]]
⁽0(ḃs      First helper link. Argument: 3

⁽0(        Numeric literal; yield 13041.
   ḃ       Convert 13041 to bijective base 3, yielding [1, 2, 2, 2, 1, 2, 2, 2, 3].
    s      Split the result into chunks of length 3, yielding the aforementioned
           2D array.

1

APL(NARS),90个字符,180个字节

{a⊃⍨⍵⊃⍋↑¨a←{⍵[⍋⍵]}¨a/⍨{1=∨/⍵}¨a←{(-/k),(×/2,⍵),+/k←⍵*2}¨a/⍨{>/⍵}¨a←,a∘.,a←⍳(⌊2⍟2+⍵)×9+⌊√⍵}

如果上面函数的参数是⍵,则上面的函数将返回数组的索引⍵(从1开始)的元素,该元素具有毕达哥拉斯三元组(a,b,c),其中a <= b <= c和该数组首先是对a的排序(一侧更短),然后对b进行排序(另一侧不是斜边)。会有问题,因为也没有看到我在哪里订购b ...测试:

  f←{a⊃⍨⍵⊃⍋↑¨a←{⍵[⍋⍵]}¨a/⍨{1=∨/⍵}¨a←{(-/k),(×/2,⍵),+/k←⍵*2}¨a/⍨{>/⍵}¨a←,a∘.,a←⍳(⌊2⍟2+⍵)×9+⌊√⍵}
  f¨1..10
3 4 5  5 12 13  7 24 25  8 15 17  9 40 41  11 60 61  12 35 37  13 84 85  15 112 113  16 63 65  

它与http://oeis.org/A020884相关 http://oeis.org/A020884/b020884.txt相关

A020884:原始毕达哥拉斯三角形的有序短腿。

  ↑¨f¨1..23
3 5 7 8 9 11 12 13 15 16 17 19 20 20 21 23 24 25 27 28 28 29 31 
  f 999
716 128163 128165 
  f 1000
717 28556 28565 

我不知道它是否正确,似乎函数会给出三角形的第一边的正确结果,直到1000,但我不知道其余的余量,甚至可能小于<1000的三倍。


0

JavaScript,101个字节

通过Euclid公式,所有原始毕达哥拉斯三元组都可以从整数生成,m并且n带有m>n>0m+n奇数gcd(m,n)==1Wikipedia

此函数枚举所有m,n对从m开始递增,从2开始m=2递减n2 m-1(因此m+n为奇数)

c=>eval("g=(a,b)=>b?g(b,a%b):a;for(m=2,n=1;c-=g(m,n)<2;(n-=2)>0||(n=m++));[m*m-n*n,2*m*n,m*m+n*n]")

少打高尔夫球

c => {
  g = (a,b) => b ? g(b,a%b) : a;
  for( m = 2, n = 1; 
       g(m,n) < 2 ? --c : c; 
       (n -= 2) > 0 || (n = m++))
    /* empty for body */;
  return [m*m - n*n, 2*m*n, m*m + n*n]
}

测试

F=
c=>eval("g=(a,b)=>b?g(b,a%b):a;for(m=2,n=1;c-=g(m,n)<2;(n-=2)>0||(n=m++));[m*m-n*n,2*m*n,m*m+n*n]")

for(i=1;i<=50;i++) console.log(i+' '+F(i))

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.