Masalah Josephus (menghitung)

29

Tantangan

Tulis fungsi yang mengambil dua bilangan bulat positif n dan k sebagai argumen dan mengembalikan jumlah orang terakhir yang tersisa dari n setelah menghitung masing-masing orang ke- k .

Ini adalah tantangan kode-golf, sehingga kode terpendek menang.

Masalah

n orang (yang diberi nomor dari 1 hingga n ) berdiri dalam lingkaran dan setiap k dihitung hingga satu orang tersisa (lihat artikel wikipedia yang sesuai ). Tentukan jumlah orang terakhir ini.

Misalnya untuk k = 3 dua orang akan dilewati dan yang ketiga akan dihitung. Yaitu untuk n = 7 angkanya akan dihitung dalam urutan 3 6 2 7 5 1 (secara detail 1 2 3 4 5 6 7 1 2 4 5 7 1 4 5 1 4 1 4 ) dan dengan demikian jawabannya adalah 4 .

Contohnya

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
Howard
sumber

Jawaban:

5

GolfScript, 17 byte

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

Mengambil n ktumpukan, dan meninggalkan hasilnya di tumpukan.

Pembedahan

Ini menggunakan pengulangan g(n,k) = (g(n-1,k) + k) % ndengan g(1, k) = 0(seperti yang dijelaskan dalam artikel Wikipedia) dengan rekursi diganti dengan lipatan.

{          # 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;
Peter Taylor
sumber
Bisakah Anda menambahkan penjelasan?
Sherlock9
@ Sherlock9, saya berhasil mengetahui apa yang saya lakukan meskipun sudah hampir 3,5 tahun berlalu. Siapa bilang GolfScript hanya-baca? ;)
Peter Taylor
Ahem. s / baca / tulis /
Peter Taylor
Maaf. Saya baru mulai belajar Golfscript dua atau tiga hari yang lalu dan saya setiap kali saya membaca kode Anda, saya terus berpikir saya melewatkan sesuatu. ... Ok, aku masih kehilangan sesuatu, bagaimana lipat {k block}lebih [0..n-1]mendapatkan Anda g(0,k) 0 kuntuk memulai dengan? Maaf, jika saya memposting pertanyaan ini di tempat yang salah.
Sherlock9
@ Sherlock9, lipat berfungsi berpasangan, jadi hal pertama yang dilakukan adalah mengevaluasi 0 1 block. Sangat mudah, itu kebetulan terjadi g(1, k) (2-1) block. Jadi itu mulai dari pada g(1,k) 1bukan g(0,k) 0. Kemudian setelah menjalankan blok, ia mendorong item berikutnya dari array ( 2) dan mengeksekusi blok lagi, dll.
Peter Taylor
14

Mesin Pendaftaran Minsky (25 negara bagian)

Secara teknis bukan fungsi, tetapi dalam paradigma komputasi yang tidak memiliki fungsi ...

Ini adalah sedikit variasi pada kasus uji utama tantangan interpretasi MRM pertama saya : Masalah Josephus sebagai mesin register Minsky

Masukan dalam register ndan k; output dalam register r; diasumsikan bahwa r=i=t=0pada entri. Dua instruksi penghentian pertama adalah kasus kesalahan.

Peter Taylor
sumber
Saya pikir Anda harus sedikit menyesuaikan mesin Anda. Jika saya membacanya dengan benar, hasilnya nol-diindeks, bukan?
Howard
Saya berpikir sebaliknya: kalau k=1begitu r=0. Hmm, saya harus memikirkan yang ini lagi ...
Howard
Saat saya membaca diagram Anda, ihanya menghitung dari 2hingga nsementara radalah register yang mengakumulasikan hasilnya.
Howard
@ Howard, saya mencari komentar yang saya buat ketika saya pertama kali menulis ini dan Anda benar. Aduh. Sekarang dikoreksi (saya percaya - akan menguji lebih teliti nanti).
Peter Taylor
7

Python, 36

Saya juga menggunakan rumus dari wikipedia:

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

Contoh:

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

Mathematica, 38 36 byte

Rumus Wikipedia yang sama:

1~f~_=1
n_~f~k_:=Mod[f[n-1,k]+k,n,1]
Tuan Wisaya
sumber
1
If[#<2,1,Mod[#0[#-1,#2]+#2,#,1]]&
alephalpha
5

C, 40 karakter

Ini hanya rumus yang diberikan oleh artikel wikipedia di atas:

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

Untuk variasi, inilah implementasi yang benar-benar menjalankan simulasi (99 karakter):

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;}
kotak roti
sumber
4
Simpan karakter: j(n,k){return--n?(j(n,k)+k-1)%-~n+1:1;}.
ugoren
5

dc, 27 byte

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

Menggunakan pengulangan dari artikel Wikipedia. Penjelasan:

# 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)
Geoff Reedy
sumber
4

J, 45 karakter

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

Menjalankan simulasi.

Atau, gunakan rumus (31 karakter):

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

Saya berharap Howard tidak keberatan bahwa saya telah menyesuaikan format input sedikit agar sesuai dengan kata kerja diad di J.

Pemakaian:

   7 j 3
4
   123 j 12
21
Gareth
sumber
4

GolfScript, 32 24 byte

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

Penggunaan: Mengharapkan dua parameter n dan k berada di tumpukan dan meninggalkan nilai output.

(terima kasih kepada Peter Taylor untuk menyarankan pendekatan berulang dan banyak tips lainnya)

Pendekatan lama (rekursif) dari 32 karakter:

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

Ini GolfScript pertama saya, jadi tolong beri tahu saya kritik Anda.

Cristian Lupascu
sumber
1
1-memiliki opcode khusus (. Demikian 1+juga ). Anda tidak harus menggunakan karakter alfabet untuk penyimpanan, jadi Anda bisa menggunakan mis. ^Alih-alih Jdan tidak perlu spasi setelahnya. Anda memiliki jauh lebih banyak $daripada biasanya dalam program golf yang bagus: pertimbangkan apakah Anda dapat menguranginya menggunakan beberapa kombinasi \@..
Peter Taylor
@PeterTaylor Terima kasih banyak atas kiat-kiat hebat ini! Cukup sulit untuk memahami semua operator Golfscript dan saya mengabaikan keduanya dengan sangat mudah. Hanya dengan menerapkan dua saran pertama saya berhasil mempersingkat kode dengan 5 karakter. Saya juga akan mencoba untuk menghapus $referensi.
Cristian Lupascu
1
Juga, rekursi sebenarnya bukan hal GolfScript. Cobalah membalikkannya dan lakukan perulangan. Saya bisa mendapatkannya hingga 19 karakter (meskipun kode yang belum diuji) seperti itu. Petunjuk: membuka gulungan fungsi gdari artikel Wikipedia, dan gunakan ,dan /.
Peter Taylor
1
{,{\2$+\)%}*)\;}:f;Pastikan Anda mengerti mengapa ini bekerja;)
Peter Taylor
1
Satu trik terakhir: daripada menggunakan 2 karakter untuk mengakses kdi dalam loop dan kemudian 2 lagi untuk membuangnya di akhir, kita bisa menariknya ke dalam menggunakan +untuk turun ke 17 karakter: {{@+\)%}+\,*)}:f;Saya ragu itu bisa ditingkatkan.
Peter Taylor
3

Groovy, 36 byte

def j(n,k){n>1?(j(n-1,k)+k-1)%n+1:1}
Pangeran John Wesley
sumber
2

Haskell, 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

Apakah simulasi yang sebenarnya. Demonstrasi:

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

berhenti mengubah counterclockwis
sumber
2

Scala, 53 byte

def?(n:Int,k:Int):Int=if(n<2)1 else(?(n-1,k)+k-1)%n+1
Pangeran John Wesley
sumber
1

C, 88 karakter

Apakah simulasi, tidak menghitung rumus.
Jauh lebih lama dari rumus, tetapi lebih pendek dari simulasi C lainnya.

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

Catatan:
1. Mengalokasikan memori dan tidak pernah melepaskan.
2. Alokasikan n*8bukannya n*4, karena saya gunakan p[n]. Bisa mengalokasikan (n+1)*4, tetapi lebih banyak karakter.

ugoren
sumber
1

C ++, 166 byte

Golf:

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

Tidak Terkumpul:

#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;
}
Michelfrancis Bustillos
sumber
2
Anda dapat menyimpan byte pada Jfungsi tersebut, dengan menggunakan operator ternary.
Yytsi
intndalam versi golf Anda tidak akan dikompilasi
Felipe Nardi Batista
Anda dapat menghapus ruang dalam#include <list>
Felipe Nardi Batista
1

J, 8 byte

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)
Richard Donovan
sumber
1
Bukankah seharusnya mengambil dua input?
Erik the Outgolfer
1

Ruby, 39 byte

def J(n,k)
n<2?1:(J(n-1,k)+k-1)%n+1
end

Menjalankan versi dengan kasus uji: http://ideone.com/pXOUc

Cristian Lupascu
sumber
1

Q, 34 byte

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

Pemakaian:

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

Ruby, 34 byte

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

Haskell, 29

Menggunakan rumus dari wikipedia.

1#_=1
n#k=mod((n-1)#k+k-1)n+1
alephalpha
sumber
0

JavaScript (ECMAScript 5), 48 byte

Menggunakan ECMAScript 5 karena itu adalah versi terbaru dari JavaScript pada saat pertanyaan ini diajukan.

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

Versi ES6 (non-bersaing), 33 byte

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

Penjelasan

Tidak banyak bicara di sini. Saya hanya mengimplementasikan fungsi yang diberikan artikel Wikipedia kepada saya.

Luke
sumber
0

05AB1E , 11 byte

L[Dg#²<FÀ}¦

Cobalah online!

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
Riley
sumber
0

8 , 82 byte

Kode

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

SED (Stack Effect Diagram) adalah:n k -- m

Penggunaan dan penjelasan

Algoritma menggunakan array bilangan bulat seperti ini: jika nilai orang adalah 5 maka array akan menjadi [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
Kekacauan Manor
sumber
0

J , 24 byte

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

Cobalah online!

Pendekatan berulang berdasarkan solusi pemrograman dinamis.

Penjelasan

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
mil
sumber
0

J , 19 byte

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

Cobalah online!

Bagaimana itu bekerja

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
Bubbler
sumber
0

Japt , 15 byte

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

Cobalah online!

Satu byte bisa disimpan dengan pengindeksan 0 k , tetapi sebenarnya bukan indeks, jadi saya memutuskan untuk tidak melakukannya.

Penjelasan:

         [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
Kamil Drakari
sumber
0

Powershell, 56 byte

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

Penting! Script menyebut dirinya secara rekursif. Jadi simpan skrip sebagaif.ps1 file di direktori saat ini. Anda juga dapat memanggil variabel blok skrip alih-alih file skrip (lihat skrip pengujian di bawah). Panggilan itu memiliki panjang yang sama.

Skrip uji:

$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"
}

Keluaran:

True: 7
True: 7
True: 4
True: 1
True: 1
True: 21
mazzy
sumber