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

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
GRC
источник
6

Mathematica, 38 36 байт

Та же формула Википедии:

1~f~_=1
n_~f~k_:=Mod[f[n-1,k]+k,n,1]
Mr.Wizard
источник
1
If[#<2,1,Mod[#0[#-1,#2]+#2,#,1]]&
алефальфа
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
Gareth
источник
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;я сомневаюсь, что это можно улучшить.
Питер Тейлор
3

Groovy, 36 байт

def j(n,k){n>1?(j(n-1,k)+k-1)%n+1:1}
Принц Джон Уэсли
источник
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

перестал поворачиваться против часовой стрелки
источник
2

Scala, 53 байта

def?(n:Int,k:Int):Int=if(n<2)1 else(?(n-1,k)+k-1)%n+1
Принц Джон Уэсли
источник
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, но это больше символов.

ugoren
источник
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

Рубин, 39 байт

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

Рабочая версия с тестовыми примерами: http://ideone.com/pXOUc

Кристиан Лупаску
источник
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
tmartin
источник
1

Рубин, 34 байта

J=->n,k{n<2?1:(J(n-1,k)+k-1)%n+1}
Hauleth
источник
0

Хаскелл, 29

Используя формулу из википедии.

1#_=1
n#k=mod((n-1)#k+k-1)n+1
alephalpha
источник
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
Chaos Manor
источник
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
Mazzy
источник