Vấn đề Josephus (tính ra)


29

Các thách thức

Viết hàm lấy hai số nguyên dương nk làm đối số và trả về số người cuối cùng còn lại sau n sau khi tính ra mỗi người thứ k .

Đây là một thử thách chơi gôn, vì vậy mã ngắn nhất sẽ thắng.

Vấn đề

n người (được đánh số từ 1 đến n ) đang đứng trong một vòng tròn và mỗi k -th được tính cho đến khi một người còn lại (xem bài viết wikipedia tương ứng ). Xác định số của người cuối cùng này.

Ví dụ: k = 3 hai người sẽ bị bỏ qua và người thứ ba sẽ bị loại. Tức là với n = 7, các số sẽ được tính theo thứ tự 3 6 2 7 5 1 (chi tiết 1 2 3 4 5 6 7 1 2 4 5 7 1 4 5 1 4 1 4 ) và do đó câu trả lời là 4 .

Ví dụ

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

Câu trả lời:


5

GolfScript, 17 byte

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

Đưa n kvào ngăn xếp và để lại kết quả trên ngăn xếp.

Mổ xẻ

Điều này sử dụng sự lặp lại g(n,k) = (g(n-1,k) + k) % nvới g(1, k) = 0(như được mô tả trong bài viết Wikipedia) với đệ quy được thay thế bằng một nếp gấp.

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

Bạn có thể thêm một lời giải thích, xin vui lòng?
Sherlock9

@ Sherlock9, tôi đã tìm ra những gì tôi đã làm mặc dù đã gần 3,5 năm trôi qua. Ai nói rằng GolfScript chỉ đọc? ;)
Peter Taylor

À. s / đọc / viết /
Peter Taylor

Lấy làm tiếc. Tôi mới chỉ bắt đầu học Golfscript hai hoặc ba ngày trước và mỗi lần đọc mã của bạn, tôi cứ nghĩ mình đã bỏ lỡ điều gì đó. ... Ok, tôi vẫn còn thiếu một cái gì đó, làm thế nào để gấp {k block}lại [0..n-1]giúp bạn g(0,k) 0 kbắt đầu? Xin lỗi, nếu tôi đăng những câu hỏi này không đúng chỗ.
Sherlock9

@ Sherlock9, gấp hoạt động theo cặp, vì vậy điều đầu tiên nó làm là đánh giá 0 1 block. Rất thuận tiện, điều đó xảy ra g(1, k) (2-1) block. Vì vậy, nó bắt đầu từ g(1,k) 1chứ không phải g(0,k) 0. Sau đó, sau khi thực hiện khối, nó đẩy mục tiếp theo từ mảng ( 2) và thực hiện lại khối, v.v.
Peter Taylor

14

Máy đăng ký Minsky (25 trạng thái không dừng)

Về mặt kỹ thuật không phải là một chức năng, nhưng nó nằm trong mô hình điện toán không có chức năng ...

Đây là một biến thể nhỏ trong trường hợp thử nghiệm chính của thử thách diễn giải MRM đầu tiên của tôi : Vấn đề Josephus là máy đăng ký Minsky

Đầu vào trong sổ đăng ký nk; đầu ra trong đăng ký r; nó được giả định rằng r=i=t=0trên mục nhập. Hai hướng dẫn tạm dừng đầu tiên là trường hợp lỗi.


Tôi nghĩ rằng bạn phải điều chỉnh máy của bạn một chút. Nếu tôi đọc chính xác thì đầu ra không có chỉ mục, phải không?
Howard

Tôi đã suy nghĩ theo cách khác: nếu k=1sau đó r=0. Hmm, tôi phải suy nghĩ lại về điều này một lần nữa ...
Howard

Khi tôi đọc sơ đồ của bạn, ichỉ đơn giản là đếm từ 2đến nlúc đó rlà thanh ghi tích lũy kết quả.
Howard

@ Xin chào, tôi đã tra cứu những bình luận tôi đã viết khi lần đầu tiên viết bài này và bạn nói đúng. Rất tiếc. Bây giờ sửa chữa (tôi tin - sẽ kiểm tra kỹ hơn sau).
Peter Taylor

7

Con trăn, 36

Tôi cũng đã sử dụng công thức từ wikipedia:

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

Ví dụ:

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

6

Toán học, 38 36 byte

Cùng một công thức Wikipedia:

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 ký tự

Đây là khá nhiều công thức mà bài viết wikipedia liên kết ở trên đưa ra:

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

Để đa dạng, đây là một triển khai thực sự chạy mô phỏng (99 ký tự):

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
Lưu một ký tự : 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

Sử dụng sự tái phát từ bài viết Wikipedia. Giải trình:

# 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 ký tự

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

Chạy mô phỏng.

Ngoài ra, sử dụng công thức (31 ký tự):

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

Tôi hy vọng Howard không bận tâm rằng tôi đã điều chỉnh định dạng đầu vào một chút cho phù hợp với động từ dyadic trong J.

Sử dụng:

   7 j 3
4
   123 j 12
21

4

GolfScript, 32 24 byte

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

Cách sử dụng: Yêu cầu hai tham số nk nằm trong ngăn xếp và để lại giá trị đầu ra.

(cảm ơn Peter Taylor đã gợi ý cách tiếp cận lặp lại và nhiều lời khuyên khác)

Cách tiếp cận cũ (đệ quy) của 32 ký tự:

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

Đây là GolfScript đầu tiên của tôi, vì vậy xin vui lòng cho tôi biết những lời chỉ trích của bạn.


1
1-có opcode đặc biệt (. Tương tự 1+là vậy ). Bạn không phải sử dụng các ký tự chữ cái để lưu trữ, vì vậy bạn có thể sử dụng ví dụ ^thay vì Jvà không cần một khoảng trắng sau nó. Bạn có nhiều $s hơn bình thường trong một chương trình được chơi tốt: xem xét liệu bạn có thể giảm chúng bằng cách sử dụng một số kết hợp \@..
Peter Taylor

@PeterTaylor Cảm ơn rất nhiều vì những lời khuyên tuyệt vời này! Thật khó để nắm bắt tất cả các nhà khai thác Golfscript và tôi đã bỏ qua hai điều này rất đơn giản. Chỉ bằng cách áp dụng hai gợi ý đầu tiên, tôi quản lý để rút ngắn mã bằng 5 ký tự. Tôi cũng sẽ cố gắng loại bỏ các $tài liệu tham khảo.
Cristian Lupascu

1
Ngoài ra, đệ quy không thực sự là điều của GolfScript. Hãy thử lật nó và làm một vòng lặp. Tôi có thể lấy nó xuống còn 19 ký tự (mặc dù mã chưa được kiểm tra) theo cách đó. Gợi ý: bỏ chức năng gtừ bài viết Wikipedia, và sử dụng ,/.
Peter Taylor

1
{,{\2$+\)%}*)\;}:f;Hãy chắc chắn rằng bạn hiểu lý do tại sao nó hoạt động;)
Peter Taylor

1
Một mẹo cuối cùng: thay vì sử dụng 2 ký tự để truy cập kvào vòng lặp và sau đó thêm 2 ký tự để loại bỏ nó ở cuối, chúng ta có thể kéo nó vào bên trong bằng cách sử dụng +để giảm xuống 17 ký tự: {{@+\)%}+\,*)}:f;Tôi nghi ngờ điều đó có thể được cải thiện.
Peter Taylor



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

Liệu mô phỏng thực tế. Trình diễn:

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 ký tự

Liệu mô phỏng, không tính toán công thức.
Dài hơn nhiều so với công thức, nhưng ngắn hơn so với mô phỏng C khá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;
}

Ghi chú:
1. Phân bổ bộ nhớ và không bao giờ phát hành.
2. Phân bổ n*8thay vì n*4, vì tôi sử dụng p[n]. Có thể phân bổ (n+1)*4, nhưng đó là nhiều nhân vật hơn.


1

C ++, 166 byte

Chơi gôn

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

Ung dung:

#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
Bạn có thể lưu byte trên Jhàm, bằng cách sử dụng toán tử ternary.
Yytsi

intntrong phiên bản chơi gôn của bạn sẽ không được biên dịch
Felipe Nardi Batista

bạn có thể xóa không gian trong#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)

1
Nó không phải là để có hai đầu vào?
Erik the Outgolfer


1

Q, 34 byte

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

Sử dụng:

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


0

Haskell, 29

Sử dụng công thức từ wikipedia.

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

0

JavaScript (ECMAScript 5), 48 byte

Sử dụng ECMAScript 5 vì đó là phiên bản JavaScript mới nhất tại thời điểm câu hỏi này được hỏi.

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

Phiên bản ES6 (không cạnh tranh), 33 byte

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

Giải trình

Không có nhiều để nói ở đây. Tôi chỉ đang thực hiện chức năng mà bài viết Wikipedia cung cấp cho tôi.



0

8 , 82 byte

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

SED (Sơ đồ hiệu ứng ngăn xếp) là:n k -- m

Cách sử dụng và giải thích

Thuật toán sử dụng một mảng các số nguyên như thế này: nếu giá trị của mọi người là 5 thì mảng đó sẽ là [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 byte

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

Hãy thử trực tuyến!

Một cách tiếp cận lặp lại dựa trên giải pháp lập trình động.

Giải trình

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 byte

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

Hãy thử trực tuyến!

Làm thế nào nó hoạt động

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 byte

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

Hãy thử trực tuyến!

Một byte có thể được lưu bằng cách lập chỉ mục 0 , nhưng thực tế nó không phải là một chỉ mục nên tôi quyết định chống lại điều đó.

Giải trình:

         [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 byte

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

Quan trọng! Kịch bản gọi chính nó đệ quy. Vì vậy, tiết kiệm kịch bản như f.ps1tập tin trong thư mục hiện hành. Ngoài ra, bạn có thể gọi một biến khối tập lệnh thay vì tập tin tập lệnh (xem tập lệnh kiểm tra bên dưới). Các cuộc gọi đó có cùng độ dài.

Kịch bản thử nghiệm:

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

Đầu ra:

True: 7
True: 7
True: 4
True: 1
True: 1
True: 21
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.