Проблема Иосифа (считая)


29

Соревнование

Напишите функцию, которая принимает два положительных целых числа n и k в качестве аргументов и возвращает номер последнего человека, оставшегося из n после отсчета каждого k-го человека.

Это задача игры в гольф, поэтому выигрывает самый короткий код.

Проблема

n человек (от 1 до n ) стоят по кругу, и каждый k-й отсчитывается до тех пор, пока не останется один человек (см. соответствующую статью в Википедии ). Определите номер этого последнего человека.

Например, при 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

Ответы:


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;

Можете ли вы добавить объяснение, пожалуйста?
Sherlock9

@ Sherlock9, мне удалось понять, чем я занимаюсь, несмотря на то, что прошло почти 3,5 года. Кто сказал, что GolfScript доступен только для чтения? ;)
Питер Тейлор

Гм. s / чтение / запись /
Питер Тейлор

Сожалею. Я только начал изучать Golfscript два или три дня назад, и каждый раз, когда я читал твой код, я думал, что что-то пропустил. ... Хорошо, я все еще не хватает кое - что, как делает складной {k block}над [0..n-1]получить вас g(0,k) 0 kначать? Извините, если я публикую эти вопросы не в том месте.
Sherlock9

@ Sherlock9, сгиб работает попарно, поэтому первое, что он делает, это оценивает 0 1 block. Очень удобно, что это происходит g(1, k) (2-1) block. Так что это начинается с, g(1,k) 1а не g(0,k) 0. Затем, выполнив блок, он выталкивает следующий элемент из array ( 2) и снова выполняет блок и т. Д.
Питер Тейлор

14

Minsky Register Machine (25 состояний без остановки)

Технически это не функция, но это компьютерная парадигма, которая сама по себе не имеет функций ...

Это небольшое изменение в основном тестовом примере моей первой задачи интерпретации MRM : Проблема Иосифа как Минский зарегистрировать машину

Ввод в регистры nи k; вывод в регистр r; Предполагается, что r=i=t=0на входе. Первые две инструкции остановки являются ошибочными случаями.


Я думаю, что вы должны немного настроить свою машину. Если я правильно прочитал, то выходные данные не проиндексированы, не так ли?
Говард

Я думал иначе: если k=1тогда r=0. Хм, я должен снова подумать об этом ...
Говард

Когда я читаю вашу диаграмму, iпросто считается от того, 2в nто время rкак регистр, который накапливает результат.
Говард

@ Говард, я посмотрел комментарии, которые я сделал, когда впервые написал это, и ты прав. Упс. Сейчас поправлю (верю - позже опробую внимательнее).
Питер Тейлор

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

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

постоянный ток, 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+\%:^;}/^)

Использование: Ожидает, что два параметра n и k находятся в стеке, и оставляет выходное значение.

(спасибо Питеру Тейлору за предложенный итеративный подход и множество других советов)

Старый (рекурсивный) подход из 32 символов:

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

Это мой первый GolfScript, поэтому, пожалуйста, дайте мне знать вашу критику.


1
1-имеет специальный код операции (. Точно так же 1+есть ). Вам не нужно использовать алфавитные символы для хранения, так что вы можете использовать, например, ^вместо Jи без пробела после него. У вас гораздо больше, $чем обычно в хорошо сыгранной программе: подумайте, сможете ли вы уменьшить их, используя некоторую комбинацию \@..
Питер Тейлор

@PeterTaylor Большое спасибо за эти замечательные советы! Довольно сложно понять все операторы Golfscript, и я упустил из виду эти два очень простых. Только применяя первые два предложения, мне удается сократить код на 5 символов. Я также постараюсь удалить $ссылки.
Кристиан Лупаску

1
Кроме того, рекурсия на самом деле не вещь для GolfScript. Попробуйте перевернуть его и сделать цикл. Таким образом, я могу получить до 19 символов (хотя и не проверенных). Подсказка: разверните функцию gиз статьи в Википедии и используйте ,и /.
Питер Тейлор

1
{,{\2$+\)%}*)\;}:f;Убедитесь, что вы понимаете, почему это работает;)
Питер Тейлор

1
Последний трюк: вместо того, чтобы использовать 2 символа для доступа kвнутри цикла, а затем еще 2 для его удаления в конце, мы можем использовать его +для сокращения до 17 символов: {{@+\)%}+\,*)}:f;я сомневаюсь, что это можно улучшить.
Питер Тейлор





1

С, 88 символов

Выполняет симуляцию, не рассчитывает формулу.
Гораздо длиннее, чем формула, но короче, чем другие симуляции Си.

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 байт

Golfed:

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

Ungolfed:

#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
Разве это не должно принимать два входа?
Эрик 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


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

объяснение

Не так много, чтобы сказать здесь. Я просто реализую функцию, которую дает мне статья в Википедии.



0

восьмых , 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

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
Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.