计算欧拉数


17

欧拉数 A(n, m)是排列的数量[1, 2, ..., n]精确地在其中m元件是比以前的元件大。这些也称为上升。例如,如果,则为n = 33!= 6个排列[1, 2, 3]

1 2 3
 < <  2 elements are greater than the previous

1 3 2
 < >  1 ...

2 1 3
 > <  1 ...

2 3 1
 < >  1 ...

3 1 2
 > <  1 ...

3 2 1
 > >  0 ...

因此A(3, m)min 的输出[0, 1, 2, 3]将是

A(3, 0) = 1
A(3, 1) = 4
A(3, 2) = 1
A(3, 3) = 0

同样,这是OEIS序列A173018

规则

  • 这是因此最短的代码获胜。
  • 输入n将是非负整数,并且m将是range内的整数[0, 1, ..., n]

测试用例

n   m   A(n, m)
0   0   1
1   0   1
1   1   0
2   0   1
2   1   1
2   2   0
3   0   1
3   1   4
3   2   1
3   3   0
4   0   1
4   1   11
4   2   11
4   3   1
4   4   0
5   1   26
7   4   1191
9   5   88234
10  5   1310354
10  7   47840
10  10  0
12  2   478271
15  6   311387598411
17  1   131054
20  16  1026509354985
42  42  0

n, m什么限制吗?
Loovjo

没有限制,但是不要求您的提交能够在一定时间内完全执行测试用例,只需要具有正确的逻辑即可。最好是,我希望提交的内容最多可以处理20个值,但是我对它的性能没有要求,只能允许暴力破解解决方案最多只能解决个问题n = 10
英里

输入是否可以使m> = n,n> 0?
feersum '16

不应该,“ m是[0,1,...,n]范围内的整数”是“ ... [0,1,...,n-1]”吗?
乔纳森·艾伦

@feersum m如果需要,您的解决方案可以支持任何方法,但我只要求它对于0 <= m <= n和0 <= n才有效
英里

Answers:


9

果冻,8 字节

Œ!Z>2\Sċ

在线尝试!(花一些时间)或验证较小的测试用例

怎么运行的

Œ!Z>2\Sċ  Main link. Arguments: n, m

Œ!        Generate the matrix of all permutations of [1, ..., n].
  Z       Zip/transpose, placing the permutations in the columns.
   >2\    Compare columns pairwise with vectorizing greater-than.
          This generates a 1 in the column for each rise in that permutation.
      S   Compute the vectorizing sum of the columns, counting the number of rises.
       ċ  Count how many times m appears in the computed counts.

6

JavaScript(ES6),50 46 45字节

f=(n,m,d=n-m)=>m?d&&f(--n,m)*++m+f(n,m-2)*d:1

基于递归公式:

A(n, m) = (n - m)A(n - 1, m - 1) + (m + 1)A(n - 1, m)    

测试用例


4

MATL,10字节

:Y@!d0>s=s

在线尝试!

说明

以输入为例n=3m=1。您可以放置​​一个%符号以注释掉此后的代码,从而查看中间结果。例如,该链接显示了第一步之后的堆栈。

:      % Input n implicitly. Push [1 2 ... n]
       % STACK: [1 2 ... n]
Y@     % Matrix of all permutations, one on each row
       % STACK: [1 2 3; 1 3 2; 2 1 3; 2 3 1; 3 1 2; 3 2 1]
!      % Transpose
       % STACK: [1 1 2 2 3 3; 2 3 1 3 1 2; 3 2 3 1 2 1]
d      % Consecutive differences along each column
       % STACK: [1 2 -1 1 -2 -1; 1 -1 2 -2 1 -1]
0>     % True for positive entries
       % STACK: [1 1 0 1 0 0; 1 0 1 0 1 0]
s      % Sum of each column
       % STACK: [2 1 1 1 1 0]
=      % Input m implicitly. Test each entry for equality with m
       % STACK: [0 1 1 1 1 0]
s      % Sum. Implicitly display
       % STACK: 4

4

CJam(21个 19字节-如果参数顺序可用,则为18个字节)

{\e!f{2ew::>1b=}1b}

这是一个匿名块(函数),它n m位于堆栈上。(如果允许将其m n放在堆栈上,则\可以保存)。它计算所有排列和过滤器,因此在线测试套件必须相当有限。

感谢Martin指出近似于filter-with-parameter

解剖

{        e# Define a block. Stack: n m
  \      e#   Flip the stack to give m n
  e!f{   e#   Generate permutations of [0 .. n-1] and map with parameter m
    2ew  e#     Stack: m perm; generate the list of n-1 pairs of consecutive
         e#     elements of perm
    ::>  e#     Map each pair to 1 if it's a rise and 0 if it's a fall
    1b   e#     Count the falls
    =    e#     Map to 1 if there are m falls and 0 otherwise
  }
  1b     e#   Count the permutations with m falls
}

请注意,欧拉数是对称的:E(n, m) = E(n, n-m),因此无论计数是下降还是上升都是无关紧要的。

有效:32个字节

{1a@{0\+_ee::*(;\W%ee::*W%.+}*=}

在线测试套件

这实现了整行的重复。

{          e# Define a block. Stack: n m
  1a@      e#   Push the row for n=0: [1]; and rotate n to top of stack
  {        e#   Repeat n times:
           e#     Stack: m previous-row
    0\+_   e#     Prepend a 0 to the row and duplicate
    ee::*  e#     Multiply each element by its index
           e#     This gives A[j] = j * E(i-1, j-1)
    (;     e#     Pop the first element, so that A[j] = (j+1) * E(i-1, j)
    \W%    e#     Get the other copy of the previous row and reverse it
    ee::*  e#     Multiply each element by its index
           e#     This gives B[j] = j * E(i-1, i-1-j)
    W%     e#     Reverse again, giving B[j] = (i-j) * E(i-1, j-1)
    .+     e#     Pointwise addition
  }*
  =        e#   Extract the element at index j
}

这是通过缩短使用地图,以避免变量:{e!f{2ew::>1b=}1e=}。还是为了好玩:{e!f{2ew::>+:-}0e=}
Martin Ender

那真是愚蠢。第1e=一个解决方案中的可以是1b
Martin Ender

您可以使用自己的参数顺序
英里

3

Python,55 56字节

a=lambda n,m:n>=m>0and(n-m)*a(n-1,m-1)-~m*a(n-1,m)or m<1

repl.it上的所有测试

在OEIS上应用递归公式。
请注意,这+(m+1)*a(n-1,m)是打高尔夫球的-~m*a(n-1,m)
(可能会返回布尔值来表示10。返回True何时n<0 and m<=0m<0)。


还有多种其他方法可以处理边缘情况。m<1 ? 1 : m==n ? 0 : formula等同地处理就足够了m%n<1 ? (m<1) : formula; 或者m<1 ? (n>=0) : formula
彼得·泰勒

我明白了,只是更新感谢
乔纳森·艾伦

由于我们的答案非常相似,并且您的答案被首先发布(且简短),因此,我将继续删除我的答案。
Loovjo

@Loovjo虽然有点疯狂的调整:(无论如何,你还是从我这里获得了投票!
Jonathan Allan

3

Mathematica,59 56字节

_~f~0=1
n_~f~m_:=If[m>n,0,(n-m)f[n-1,m-1]+(m+1)f[n-1,m]]

这是一个59字节的版本,更实际地实现了该定义:

Count[Count@1/@Sign/@Differences/@Permutations@Range@#,#2]&

为什么不只f[n_,m_]:=...为49?
乔纳森·艾伦

@JonathanAllan我不确定我是否理解。那如何处理基本情况?
Martin Ender

好的,已缓存了一些内容-只是在新工作表中进行了操作,但由于递归限制而失败。:)
乔纳森·艾伦

还有一个公式使用了46个字节Sum[Binomial[#+1,k](#2+1-k)^#(-1)^k,{k,0,#2}]&,这可能会打更多的高尔夫球
英里

3

Python,53个字节

t=lambda n,k:n and(n-k)*t(n-1,k-1)-~k*t(n-1,k)or k==0

从OEIS递归。True1时输出布尔值n==k



2

GameMaker语言,62字节

这是A基于@Arnauld公式的递归脚本。

n=argument0;m=argument1;return (n-m)*A(n-1,m-1)+(m+1)*A(n-1,m)

有一阵子没看过!
tomsmeding


1

R,72个字节

遵循OEIS逻辑的递归函数。

A=function(n,m)if(!m)1 else if(m-n)0 else(n-m)*A(n-1,m-1)+(m+1)*A(n-1,m)

事实证明,在我尝试的不同方法之间,这一挑战非常接近。例如,使用Wikipedia公式并循环求和,结果为92个字节:

function(n,m){s=0;if(!n)1 else for(k in -1:m+1)s=c(s,(-1)^k*choose(n+1,k)*(m+1-k)^n);sum(s)}

或87字节的向量化版本:

function(n,m)if(!m)1 else sum(sapply(-1:m+1,function(k)(-1)^k*choose(n+1,k)*(m+1-k)^n))

最后是蛮力解决方案(103字节),它使用permutepackage和function 生成了所有排列的矩阵allPerms。这种方法只能起作用n<8

function(n,m){if(!m)1 else sum(apply(rbind(1:n,permute:::allPerms(n)),1,function(x)sum(diff(x)>0))==m)}

1

拍框141字节

(count(λ(x)(= x m))(for/list((t(permutations(range 1(+ 1 n)))))(count
(λ(x)x)(for/list((i(sub1 n)))(>(list-ref t(+ 1 i))(list-ref t i))))))

取消高尔夫:

(define (f n m)
  (let* ((l (range 1 (add1 n)))                ; create a list till n
         (pl (permutations l))                 ; get all permutations
         (enl (for/list ((t pl))               ; check each permutation; 
                (define rl
                  (for/list ((i (sub1 n)))     ; check if an element is a 'rise'
                    (> (list-ref t (add1 i))
                       (list-ref t i))))
                (count (lambda(x)x) rl))))     ; how many numbers are 'rises'
    (count (lambda(x) (= x m)) enl)))          ; how many permutations had m rises
                                               ; i.e. Eulerian number

测试:

(f 3 0)
(f 3 1)
(f 3 2)
(f 3 3)
(f 4 2)
(f 5 1)
(f 7 4)

输出:

1
4
1
0
11
26
1191

1

事实上21 19个字节

该答案使用的算法类似于Dennis在Jelly答案中使用的算法。<当我数数时,原始定义数数>。最后这是等效的。欢迎打高尔夫球。在线尝试!

;R╨`;\ZdX"i>"£MΣ`Mc

开球

         Implicit input m, then n.
;        Duplicate n. Stack: n, n, m
R        Push range [1..n].
╨        Push all n-length permutations of the range.
`...`M   Map the following function over each permutation p.
  ;\       Duplicate and rotate p so that we have a list of the next elements of p.
  Z        Zip rot_p and p.
           (order of operands here means the next element is first,
            so we need to use > later)
  dX       Remove the last pair as we don't compare the last and first elements of the list.
  "i>"£    Create a function that will flatten a list and check for a rise.
  M        Map that function over all the pairs.
  Σ        Count how many rises there are in each permutation.
c        Using the result of the map and the remaining m, 
          count how many permutations have m rises.
         Implicit return.


0

J,28个字节

+/@((!>:)~*(^~#\.)*_1^])i.,]

使用公式

式

用法

   f =: +/@((!>:)~*(^~#\.)*_1^])i.,]
   0 f 0
1
   1 f 0
1
   1 f 1
0
   (f"+i.,]) 6
1 57 302 302 57 1 0
   20x f 16x
1026509354985

说明

+/@((!>:)~*(^~#\.)*_1^])i.,]  Input: n (LHS), m (RHS)
                        i.    Range [0, 1, ..., m-1]
                           ]  Get m
                          ,   Join to get k = [0, 1, ..., m]
                      ]       Get k
                   _1^        Raise -1 to each in k
              #\.               Get the length of each suffix of k
                                Forms the range [m+1, m, ..., 2, 1]
            ^~                  Raise each value by n
                  *           Multiply elementwise with (-1)^k
    (   )~                      Commute operators
      >:                        Increment n
     !                          Binomial coefficient, C(n+1, k)
          *                   Multiply elementwise
+/@                           Reduce by addition to get the sum and return
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.