约瑟夫斯问题(算出)


29

挑战

编写一个函数,该函数将两个正整数nk作为参数,并在计算出每个第k人后返回n中剩余的最后一个人的人数。

这是一个代码挑战,因此以最短的代码为准。

问题

n个人(从1n编号)围成一个圈,每个k-数被计数,直到剩下一个人为止(请参阅相应的Wikipedia文章)。确定最后一位的号码。

例如,对于k = 3,两个人将被跳过,第三个将被算出。即,对于n = 7,数字将按3 6 2 7 5 1的顺序计数(详细为1 2 3 4 5 6 7 1 2 4 5 7 1 4 5 1 4 1 4),因此答案为4

例子

J(7,1) = 7      // people are counted out in order 1 2 3 4 5 6 [7]
J(7,2) = 7      // people are counted out in order 2 4 6 1 5 3 [7]
J(7,3) = 4      // see above
J(7,11) = 1
J(77,8) = 1
J(123,12) = 21

Answers:


5

GolfScript,17个字节

{{@+\)%}+\,*)}:f;

注意到n k在堆栈上,并留下堆栈上的结果。

解剖

此用途的复发g(n,k) = (g(n-1,k) + k) % ng(1, k) = 0(如维基百科文章中所描述的)与递归取代由折叠。

{          # Function declaration
           # Stack: n k
  {        # Stack: g(i-1,k) i-1 k
    @+\)%  # Stack: g(i,k)
  }+       # Add, giving stack: n {k block}
  \,*      # Fold {k block} over [0 1 ... n-1]
  )        # Increment to move from 0-based to 1-based indexing
}:f;

您能补充一下说明吗?
Sherlock15年

@ Sherlock9,尽管过去了将近3.5年,我还是设法弄清楚自己在做什么。谁说GolfScript是只读的?;)
彼得·泰勒

啊 s / read / write /
Peter Taylor

抱歉。我只是在两三天前才开始学习Golfscript,所以每次阅读您的代码时,我一直以为自己错过了一些东西。......好吧,我还是失去了一些东西,如何折叠{k block}[0..n-1]让你g(0,k) 0 k开始吗?抱歉,如果我在错误的位置发布了这些问题。
Sherlock9年9

@ Sherlock9,fold是成对工作的,所以它要做的第一件事就是评价0 1 block。非常方便,恰好是g(1, k) (2-1) block。因此,它始于g(1,k) 1而不是g(0,k) 0。然后执行块之后,它从阵列(推下一项目2),并再次执行所述块等
彼得·泰勒

14

明斯基注册机(25个非暂停状态)

从技术上讲不是功能,但是它属于计算范式,其本身不具有功能...

这与我的第一个MRM解释挑战的主要测试用例略有不同: 约瑟夫斯问题为明斯基注册机

输入寄存器nk; 寄存器输出r; 假定r=i=t=0进入时。前两个停止指令是错误情况。


我认为您必须稍微调整一下机器。如果我没看错的话,输出是零索引的,不是吗?
霍华德

我在想其他的办法:如果k=1然后r=0。嗯,我得再考虑一遍……
霍华德

当我看了你的图,i只是从计数2nr是积累的结果寄存器。
霍华德

@霍华德,我查阅了我第一次写这篇文章时发表的评论,你是对的。哎呀 现在已更正(我相信-稍后会进行更彻底的测试)。
彼得·泰勒

7

Python,36岁

我还使用了维基百科的公式:

J=lambda n,k:n<2or(J(n-1,k)+k-1)%n+1

例子:

>>> J(7,3)
4
>>> J(77,8)
1
>>> J(123,12)
21

6

Mathematica,38 36字节

相同的维基百科公式:

1~f~_=1
n_~f~k_:=Mod[f[n-1,k]+k,n,1]

1
If[#<2,1,Mod[#0[#-1,#2]+#2,#,1]]&
alephalpha

5

C,40个字符

这几乎只是上面链接的维基百科文章提供的公式:

j(n,k){return n>1?(j(n-1,k)+k-1)%n+1:1;}

对于多样性,这是一个实际运行模拟的实现(99个字符):

j(n,k,c,i,r){char o[999];memset(o,1,n);for(c=k,i=0;r;++i)(c-=o[i%=n])||(o[i]=!r--,c=k);
return i;}

4
保存字符:j(n,k){return--n?(j(n,k)+k-1)%-~n+1:1;}
ugoren

5

dc,27位元组

[d1-d1<glk+r%1+]dsg?1-skrxp

使用来自Wikipedia文章的重复记录。说明:

# comment shows what is on the stack and any other effect the instructions have
[   # n
d   # n, n
1-  # n-1, n
d   # n-1, n-1, n
1<g # g(n-1), n ; g is executed only if n > 1, conveniently g(1) = 1
lk+ # g(n-1)+(k-1), n; remember, k register holds k-1
r%  # g(n-1)+(k-1) mod n
1+  # (g(n-1)+(k-1) mod n)+1
]
dsg # code for g; code also stored in g
?   # read user input => k, n, code for g
1-  # k-1, n, code for g
sk  # n, code for g; k-1 stored in register k
r   # code for g, n
x   # g(n)
p   # prints g(n)

4

J,45个字符

j=.[:{.@{:]([:}.]|.~<:@[|~#@])^:(<:@#)>:@i.@[

运行模拟。

或者,使用公式(31个字符):

j=.1:`(1+[|1-~]+<:@[$:])@.(1<[)

我希望霍华德不介意我已经略微调整了输入格式以适合J中的二元动词。

用法:

   7 j 3
4
   123 j 12
21

4

GolfScript,32个 24字节

:k;0:^;(,{))^k+\%:^;}/^)

用法: 期望两个参数nk在堆栈中,并保留输出值。

(感谢Peter Taylor提出了一种迭代方法以及许多其他技巧)

32个字符的旧(递归)方法:

{1$1>{1$(1$^1$(+2$%)}1if@@;;}:^;

这是我的第一个GolfScript,所以请让我知道您的批评。


1
1-有特殊的操作码(。同样1+)。您不必使用字母字符进行存储,因此可以使用eg ^代替,J并且在其后不需要空格。您所拥有的$s 远远超出了完善程序中通常的s:考虑是否可以使用的某些组合来减少它们\@.
彼得·泰勒

@PeterTaylor非常感谢这些出色的提示!很难理解所有的Golfscript操作员,而我却忽略了这两个非常简单的操作员。仅通过应用前两个建议,我设法将代码缩短了5个字符。我还将尝试删除$引用。
克里斯蒂安·卢帕斯库

1
同样,递归并不是GolfScript真正的事情。尝试将其翻转并循环播放。这样我可以将其降低到19个字符(尽管未经测试的代码)。提示:g从Wikipedia文章中展开该函数,并使用,/
彼得·泰勒

1
{,{\2$+\)%}*)\;}:f;确保您了解它为什么起作用;)
彼得·泰勒

1
最后一个技巧:不要使用2个字符来访问k循环,而不必再使用2个字符来结束循环,我们可以使用+减少到17个字符来将其拉入内部:{{@+\)%}+\,*)}:f;我怀疑是否可以改进。
彼得·泰勒



2

哈斯克尔,68

j n=q$cycle[0..n]
q l@(i:h:_)k|h/=i=q(drop(k-1)$filter(/=i)l)k|1>0=i

做实际的模拟。示范:

GHCi> j 7 1
7
GHCi> j 7 2
7
GHCi> j 7 3
4
GHCi> j 7 11
1
GHCi> j 77 8
1
GHCi> j 123 12
21



1

C,88个字符

做模拟,不计算公式。
比公式长得多,但比其他C模拟短。

j(n,k){
    int i=0,c=k,r=n,*p=calloc(n,8);
    for(;p[i=i%n+1]||--c?1:--r?p[i]=c=k:0;);
    return i;
}

注意:
1.分配内存,从不释放。
2.分配n*8而不是n*4,因为我使用p[n]。可以分配(n+1)*4,但是字符更多。


1

C ++,166字节

打高尔夫球:

#include<iostream>
#include <list>
int j(int n,int k){if(n>1){return(j(n-1,k)+k-1)%n+1;}else{return 1;}}
int main(){intn,k;std::cin>>n>>k;std::cout<<j(n,k);return 0;}

取消高尔夫:

#include<iostream>
#include <list>
int j(int n,int k){
    if (n > 1){
        return (j(n-1,k)+k-1)%n+1;
    } else {
        return 1;
    }
}
int main()
{
    int n, k;
    std::cin>>n>>k;
    std::cout<<j(n,k);
    return 0;
}

2
您可以J使用三元运算符在函数上保存字节。
Yytsi'6

intn您的高尔夫版本中的内容无法编译
Felipe Nardi Batista

您可以删除其中的空间#include <list>
Felipe Nardi Batista

1

J,8个字节

1&|.&.#:

       1&|.&.#: 10
    5

       1&|.&.#: 69
    11

        1&|.&.#: 123456
    115841

        1&|.&.#: 123245678901234567890x NB. x keeps input integral
    98917405212792722853

All credit to Roger Hui, co-inventor of J and all-round uber-genius
www.jsoftware.com for free j software across many platforms

Explanation
    (J works right-to-left)
     #:       convert input to binary
     &.       a&.b <=> perform b, perform a, perform reverse of b
     1&|.     rotate bitwise one bit left

So
    1&|.&.#: 10

    a. #:            convert input (10) TO binary -> 1 0 1 0
    b. 1&|.          rotate result 1 bit left -> 0 1 0 1
    c. due to the &. perform convert FROM binary -> 5 (answer)

1
它不应该接受两个输入吗?
Erik the Outgolfer


1

Q,34个字节

f:{$[x=1;1;1+mod[;x]f[x-1;y]+y-1]}

用法:

q)f .'(7 1;7 2;7 3;7 11;77 8;123 12)
7 7 4 1 1 21

1

Ruby,34个字节

J=->n,k{n<2?1:(J(n-1,k)+k-1)%n+1}

0

29岁的哈斯克尔

使用维基百科的公式。

1#_=1
n#k=mod((n-1)#k+k-1)n+1

0

JavaScript(ECMAScript 5),48个字节

使用ECMAScript 5是因为在问这个问题时这是JavaScript的最新版本。

function f(a,b){return a<2?1:(f(a-1,b)+b-1)%a+1}

ES6版本(非竞争),33字节

f=(a,b)=>a<2?1:(f(a-1,b)+b-1)%a+1

说明

这里没有太多要说的。我只是实现Wikipedia文章给我的功能。


0

05AB1E,11个字节

L[Dg#²<FÀ}¦

在线尝试!

L           # Range 1 .. n
 [Dg#       # Until the array has a length of 1:
     ²<F }  #   k - 1 times do:
        À   #     Rotate the array
          ¦ #   remove the first element

0

8th,82字节

: j >r >r a:new ( a:push ) 1 r> loop ( r@ n:+ swap n:mod ) 0 a:reduce n:1+ rdrop ;

SED(堆栈效应图)为:n k -- m

用法与解释

该算法使用如下整数数组:如果people值为5,则该数组将为[1,2,3,4,5]

: j \ n k -- m
    >r                               \ save k
    >r a:new ( a:push ) 1 r> loop    \ make array[1:n]
    ( r@ n:+ swap n:mod ) 0 a:reduce \ translation of recursive formula with folding using an array with values ranging from 1 to n
    n:1+                             \ increment to move from 0-based to 1-based indexing
    rdrop                            \ clean r-stack
;

ok> 7 1 j . cr
7
ok> 7 2 j . cr
7
ok> 7 3 j . cr
4
ok> 7 11 j . cr
1
ok> 77 8 j . cr
1
ok> 123 12 j . cr
21

0

J,24个字节

1+1{1([:|/\+)/@,.1|.!.0#

在线尝试!

基于动态编程解决方案的迭代方法。

说明

1+1{1([:|/\+)/@,.1|.!.0#  Input: n (LHS), k (RHS)
                       #  Make n copies of k
                 1|.!.0   Shift left by 1 and fill with zero
    1          ,.         Interleave with 1
             /@           Reduce using
           +                Addition
        |/\                 Cumulative reduce using modulo
  1{                      Select value at index 1
1+                        Add 1

0

J,19个字节

1+(}:@|.^:({:@])i.)

在线尝试!

怎么运行的

1+(}:@|.^:({:@])i.)   Left: k, Right: n
                i.    Generate [0..n-1]
        ^:            Repeat:
   }:@|.                Rotate left k items, and remove the last item
          ({:@])        n-1 (tail of [0..n-1]) times
1+                    Add one to make the result one-based


0

Japt,15个字节

_é1-V Å}h[Uõ] Ì

在线尝试!

可以通过0索引k保存一个字节,但是实际上它不是索引,因此我决定反对。

说明:

         [Uõ]      :Starting with the array [1...n]
_      }h          :Repeat n-1 times:
 é1-V              : Rotate the array right 1-k times (i.e. rotate left k-1 times)
      Å            : Remove the new first element
              Ì    :Get the last value remaining


0

Powershell,56个字节

param($n,$k)if($n-lt2){1}else{((.\f($n-1)$k)+$k-1)%$n+1}

重要!该脚本以递归方式调用自身。因此,将脚本另存为f.ps1当前目录中的文件。您也可以调用脚本块变量而不是脚本文件(请参见下面的测试脚本)。该呼叫具有相同的长度。

测试脚本:

$f = {

param($n,$k)if($n-lt2){1}else{((&$f($n-1)$k)+$k-1)%$n+1}

}

@(
    ,(7, 1, 7)
    ,(7, 2, 7)
    ,(7, 3, 4)
    ,(7, 11, 1)
    ,(77, 8, 1)
    ,(123,12, 21)
) | % {
    $n,$k,$expected = $_
    $result = &$f $n $k
    "$($result-eq$expected): $result"
}

输出:

True: 7
True: 7
True: 4
True: 1
True: 1
True: 21
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.