ジョセフス問題(カウントアウト)


29

チャレンジ

2つの正の整数nkを引数として取り、各k番目の人をカウントアウトした後、nから残っている最後の人の数を返す関数を記述します。

これはコードとゴルフのチャレンジなので、最短のコードが優先されます。

問題

n人(1からnまでの番号が付けられている)が円の中に立っており、一人が残るまで各k -thがカウントされます(対応するウィキペディアの記事を参照)。この最後の人の番号を決定します。

たとえば、k = 3の場合、 2人はスキップされ、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

回答:


5

GolfScript、17バイト

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

n kスタックを取得し、結果をスタックに残します。

解剖

これは、ウィキペディアの記事で説明されているように、再帰を折り畳みに置き換えて繰り返しg(n,k) = (g(n-1,k) + k) % nを使用しg(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;

説明を追加してください。
シャーロック9

@ Sherlock9、ほぼ3.5年が経過したにもかかわらず、私は何をしていたのかを把握できました。GolfScriptは読み取り専用だと誰が言いますか?;)
ピーターテイラー

エヘム。s /読み取り/書き込み/
ピーターテイラー

ごめんなさい。私は2、3日前にGolfscriptを学び始めたばかりで、あなたのコードを読むたびに、私は何かを見逃していると考え続けました。... [OK]を、私はまだどのように折りたたみん、何かが欠けている{k block}以上[0..n-1]、あなたを取得g(0,k) 0 kして起動しますか?申し訳ありませんが、これらの質問を間違った場所に投稿している場合。
シャーロック9

@ Sherlock9、foldはペアで機能するため、最初に行うのはevaluate 0 1 blockです。非常に便利ですが、それはたまたまg(1, k) (2-1) blockです。ですから、g(1,k) 1ではなくから始まりg(0,k) 0ます。次いで、ブロックを実行した後、それは(アレイから次の項目を押し2)等、再度ブロックを実行
ピーター・テイラー

14

Minsky Register Machine(25の非停止状態)

技術的には機能ではありませんが、それ自体は機能を持たないコンピューティングパラダイムです。

これは、私の最初のMRM解釈チャレンジのメインテストケースのわずかなバリエーションです。 ミンスキーレジスタマシンとしてのジョセフス問題

レジスタnおよびk;への入力 レジスタに出力rr=i=t=0入場時に想定されています。最初の2つの停止命令はエラーの場合です。


マシンを少し調整する必要があると思います。正しく読んだ場合、出力のインデックスはゼロになりますよね?
ハワード

私は他の方法を考えていた:場合はk=1、その後r=0。うーん、私はこれについてもう一度考えなければならない...-
ハワード

私はあなたの図を読むと、i単にからカウントされる2nしながら、rその結果を蓄積するレジスタです。
ハワード

@Howard、これを最初に書いたときに書いたコメントを調べたところ、あなたは正しい。おっと。現在は修正済みです(後でテストする予定です)。
ピーターテイラー

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


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;}
ウゴレン

5

dc、27バイト

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

ウィキペディアの記事の繰り返しを使用します。説明:

# 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+\%:^;}/^)

使用法: 2つのパラメーターnkがスタック内にあることを期待し、出力値を残します。

(反復アプローチと他の多くのヒントを提案してくれたPeter Taylorに感謝します)

32文字の古い(再帰的)アプローチ:

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

これが私の最初のGolfScriptですので、あなたの批判を教えてください。


1
1-には特別なオペコードがあり(ます。同様1+)。ストレージにアルファベット文字を使用する必要^Jありません。そのため、たとえば、代わりにスペースを使用でき、その後にスペースを必要としません。$よくゴルフされているプログラムで通常よりもはるかに多くのsがあり\@.ます。
ピーターテイラー

@PeterTaylorこれらの素晴らしいヒントをありがとう!すべてのGolfscriptオペレーターを把握するのはかなり難しく、これら2つの非常に単純な1つを見落としていました。最初の2つの提案を適用することによってのみ、コードを5文字短縮できます。また、$参照を削除しようとします。
クリスチャンルパスク

1
また、再帰は実際にはGolfScriptのものではありません。ひっくり返してループしてみてください。この方法で19文字(未テストのコードではありますが)に減らすことができます。ヒント:gウィキペディアの記事から関数を展開し、とを使用,/ます。
ピーターテイラー

1
{,{\2$+\)%}*)\;}:f;なぜそれが機能するのを理解してください;)
ピーターテイラー

1
最後のトリック:kループ内でアクセスするために2文字を使用し、最後にさらに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

intnあなたのゴルフバージョンではコンパイルされません
フェリペ・ナルディ・バティスタ

スペースを削除できます#include <list>
フェリペナルディバティスタ

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
2つの入力を取ることになっていないのですか?
エリックアウトゴルファー


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



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

説明

ここで言うことはあまりありません。ウィキペディアの記事が提供する機能を実装しています。



0

8番目、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

使い方と説明

アルゴリズムは、次のような整数の配列を使用します。人々の値が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

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