Проблема Йосифа з трьома входами


22

На цьому веб-сайті є запитання, яке схоже на це питання, але я додав поворот.

У вас є три входи, кількість людей у ​​колі n , k -ма людина, що рахується на кожному кроці, і q -та людина, яка вижила. Люди в колі пронумеровані від 1 до n .

Наприклад, у колі з 20 осіб 20-та особа, яка вижила, - це перша людина, яку вижили, 19-а особа, яка вижила, - друга людина, яку вилучили тощо. Зазвичай проблема Йосифа полягає у визначенні останньої вилученої особи, яку тут називають першим уцілілим.

Напишіть найкоротшу програму або функцію, яка за допомогою цих трьох входів повертає число q- ї людини, щоб вижити.

Якщо якісь проблеми з ясністю, будь ласка, повідомте мене про це.

Деякі приклади:

>>> josephus(20, 3, 9)
4
>>> josephus(4, 3, 1)
1
>>> josephus(100, 9, 12)
46

Редагувати: Припустимо, що всі вхідні дані є дійсними. Тобто ніхто не буде запитувати 0 або будь-які негативні цифри, і ніхто не буде просити 20-го виживця в колі 5 чоловік (тобто 1 ≤ q ≤ n)

Редагувати: Я прийму відповідь опівночі UTC + 7 на початку 2 грудня.


1
Будь ласка, опублікуйте власні рішення як відповіді, а не включайте їх у запитання.
Дверна ручка

Зрозумів. Вибачте з цього приводу
Sherlock9

1
Для уточнення, якщо q=1це точно так само, як пов'язане питання Йосифа, так?
AdmBorkBork

@TimmyD Рівно
Sherlock9

Відповіді:


5

Pyth, 16 байт

eu.<PGvzh-QvwShQ

Спробуйте в Інтернеті: Демонстрація або Тестовий набір

Введення має форму k<newline>n<newline>q.

Пояснення:

eu.<PGvzh-QvwShQ   implicit: z = first input line (string)
                             Q = second input line (integer)
              hQ   Q + 1
             S     the range [1, 2, ..., Q+1]
 u      h-Qvw      apply the following statement (Q-input()+1) times to G=^
    PG                remove the last number of G
  .<  vz              and rotate eval(z) to the left
e                  print the last number of the resulting list  

7

Піт, 280 273 коделів

введіть тут опис зображення

Редагувати: Я ще трохи пограв на цьому, і, думаю, можу ще більше пограти, але це ще належить. Наразі я просто радий, що це працює, і що я мав місце підписати це в нижньому лівому куті. Дві ідеї, які мені потрібно зберегти більше кодексів, це: а) змінити кінцеві вказівки pop, push 1, add, out num(pop n, вихід r + 1) і b) повторити повторне копіювання в нижньому лівому куті, щоб згодом зберегти коделі в маніпуляції зі стеком у циклі.

На малюнку вище мій код у 8 пікселів на кодекс. Загалом, це той самий алгоритм, що і моя відповідь Python, але з введеннями в порядку k , q , n . На практиці також існує велика кількість маніпуляцій зі стеком. Ви можете спробувати тут , відкривши зображення там і запустивши з ним код.

Пояснення

Це поетапне зняття рішення з розробки.

in num    get k
dup       Stack: k k
push 1
subtract  Stack: k k-1
in num    get q
dup       Stack: k k-1 q q
dup       Stack: k k-1 q q q
push 4
push 2
roll      Stack: k q q k-1 q
mod       Stack: k q q r
in num    get n
# note: the loop will return to the following codel
dup       Stack: k q q r n n
push 4
push 3
roll      Stack: k q r n n q
greater   1 or 0
pointer   Here the loop begins. If q>n, the pointer moves clockwise.
          Else, it points straight ahead

LOOP:     Stack: k i r n (i=q at the start of the loop)
push 4
push 2
roll      Stack: r n k i
push 1
add       Stack: r n k i=i+1
push 2
push 1
roll      Stack: r n i k
dup       Stack: r n i k k
push 5
push 4
roll      Stack: n i k k r
add       Stack: n i k m=r+k
push 3
push 2
roll      Stack: n k m i
dup       Stack: n k m i i
push 3
# here it turns the corner
push 1
roll      Stack: n k i m i
mod       Stack: n k i r=m%i
push 4
# here it turns the corner and avoids the black codels
push 1
roll      Stack: r n k i
dup       Stack: r n k i i
push 5
push 3
roll      Stack: k i i r n
dup       Stack: k i i r n n
# and we meet up with the dark green codel once more
push 4
push 3
roll      Stack: k i r n n i
greater   Stack: k i r n (0 or 1)
pointer   if else again

# else    Stack: k i r n
push 2    
push 1
roll      Stack: k i n r
# and turn the corner
push 1
add       Stack: k i n r+1
out num   print r+1
# turn the corner into the end pattern (the shape with the black edges)
END

Ви не рахуєте порожнього місця? Чи є десь метапост про те, як забити Піт? Мабуть, повинно бути.
Спарр

@Sparr, я рахую порожнє місце. Це 21 кодекс на 13 кодельних зображень, тому оцінка становить 273 коделі.
Шерлок9

А-а-а, я прорахував. Вибачте.
Спарр

4

CJam, 22 20 19 байт

q~_,@a@*{m<)\}%\~=)

Це вказує на вхід як q k n. Спробуйте його в Інтернеті в інтерпретаторі CJam .

Як це працює

q~                   Read and evaluate all input. This pushes q, k, and n.
  _,                 Push A := [0 ... n-1].
    @a               Rotate on top of the stack and wrap it in an array.
      @*             Rotate the original n on top and repeat [k] n times.
        {    }%      For each of the n k's:
         m<            Rotate A k units to the left.
           )\          Pop the last element and swap it with A.
               \~    Swap the resulting array with q and apply bitwise NOT.
                 =)  Select the corresponding element and add 1 to it.

3

Гольфскрипт, 58 56 55 35 31 30 байт

Припустимо, що три входи вже знаходяться в стеку, в порядку n , k , q

~1$(1$%3$),@),-{\2$+\%}%\)])\;

Це рішення передбачає, що мені потрібно позбутися всього, крім остаточної відповіді.

Як це працює

Дивіться j(n,k,q)у моєму рішенні Python 3 для отримання більш детальної інформації.

~                                   Read the inputs n, k, q
 1$(                                Duplicate k, decrement
    1$                              Duplicate q
      %                             (k-1)%q
       3$),                         Create array [0..n+1]
           @),                      Create array [0..q+1]
              -                     Subtract the second array from the first,
                                        leaving only [q+1..n+1]
               {      }%            Map the following statement onto [q+1..n+1].
                                        The numbers from this array will be denoted i.
                \                   Swap i and r
                 2$+                Duplicate k, add to r
                    \               Swap r and i
                     %              r mod i
                        \)          Swap the leftover array from map with r, increment
                          ]         Put the whole stack into an array
                           )        Remove the last member of the array, r
                            \;      Pop the array, leaving only the result

Редагувати 1: Використовується пропозиція @ Doorknob (додано +, щоб отримати всі вхідні дані в масив)

Раніше

\.(2$2$*1$4$%-{.5$3$*>!}{~)2$*1$/~)}while 4$3$*\-)\;\;\;\;

Редагування 2: Додано ~, відповідно до правил вікі та скорочено код. Дякую @Dennis

Раніше

[\.(2$2$*1$4$%-{.5$3$*>!}{~)2$*1$/~)}while 4$3$*\-)]+)\;

Правка 3: Реалізовано коротший алгоритм.

Раніше

~\.(2$2$*1$4$%-{.5$3$*>!}{~)2$*1$/~)}while 4$3$*\-)]-1=

Правка 4: Зрозуміло, що я можу використовувати %як карту.

Раніше

~1$(1$%{1$4$<}{\)\2$+1$%}while)])\;

Правка 5: Незначне редагування. Змінений 2$для @зробити [0..q-1]і 3$для 2$витягувати k. Врятував укус

Раніше

~1$(1$%3$),2$),-{\3$+\%}%\)])\;

1
\;\;\;\;може бути замінено на ])\;(обгортання в масив, праворуч-роз'єднання, swap та pop).
Дверна ручка

Відредагував мій код для ясності @Dennis.
Шерлок9

Добре @Dennis. Додано ~ та відредагувало питання, щоб дозволити лише програми та функції. Чи є у вас інші пропозиції?
Шерлок9

Ні, все добре. :)
Денніс

2

JavaScript (ES6), 56 байт

(n,k,q)=>{r=(k-1)%q;for(i=q;i<n;r=(r+k)%++i);return r+1}

Безумовно

В основному, це адаптація JavaScript відповіді Python @ Sherlock9 .

(n,k,q)=>{
  r=(k-1)%q;
  for(i=q;i<n;r=(r+k)%++i);
  return r+1
}

Тест

n = <input type="number" id="N" value="100" /><br />
k = <input type="number" id="K" value="9" /><br />
q = <input type="number" id="Q" value="12" /><br />
<button onclick="result.innerHTML=(

(n,k,q)=>{r=(k-1)%q;for(i=q;i<n;r=(r+k)%++i);return r+1}

)(+N.value,+K.value,+Q.value)">Go</button><br />
<pre id="result"></pre>


Я б не називав вашу версію без вольфів непільгованою: P
Позов

1

Математика, 50 байт

<<Combinatorica`
Tr@Position[Josephus@##2,1+#2-#]&

Анонімна функція. Приймає входи в порядку q,n,k.


1

C, 81 73 байт

На основі реалізації @ user81655 Javascript моєї відповіді Python.

Редагувати: Видалено i

int j(int n,int k,int q){int r=(k-1)%q;for(;q<n;r=(r+k)%++q);return r+1;}

Тест

#include <stdio.h>
int j(int n,int k,int q){int r=(k-1)%q;for(;q<n;r=(r+k)%++q);return r+1;}
int main()
{
    printf("%d\n", j(20,3,9));
    return 0;
}

У деяких версіях C ви можете скинути intімена параметрів до.
Позов по

1

Пітон 3, 72 66 62 байт

Функція динамічного програмування в 62 байти. Адаптований з алгоритму у Вікіпедії. Раніше ця алгоритм була прямою реалізацією, коли q = 1 (тобто i = 1, r = 0) на цій сторінці, але я бачу, що її вже видалено.

Редагувати 1: Я видалив, iщоб зберегти 4 байти. Пояснення залишається незмінним.

Редагувати 2: Прорахунок у кількості байтів Я використовував \r\nдля EOL і не помітив, коли додав 3 байти. Я відповідно знизив кількість байтів.

def j(n,k,q):
 r=(k-1)%q
 while q<n:q+=1;r=(r+k)%q
 return r+1

Як це працює

def j(n,k,q):
 i=q;r=(k-1)%q              We start with the smallest possible circle to have a q-th
                                survivor, a circle of q people.
 while i<n:i+=1;            Iterate from q to n
                r=(r+k)%i   Every time you add people to the circle, r increases by k, 
                                modulo the current size of the circle i.
 return r+1                 Return the result.

Дякую @Dennis за те, що він нагадав мені, що я повинен пояснити свій код (хоч би неявно, тому що він включив його у свою відповідь). Якщо щось незрозуміле, будь ласка, повідомте мене про це.

Редагувати:

Раніше

Ітеративна функція, адаптована з конкретної математики Гремом, Кнутом та Паташником. Хоча цей алгоритм довший, він швидший для великих n та малих k .

def t(n,k,q):
 m=k-1;z=q*k-m%q
 while z<=n*m:z=-(-z*k//m)
 return n*k-z+1

1
Схоже, ви вирізали щось при копіюванні-вставці, там висить +.
xnor

1

PHP, 71 байт

На основі відповідей @ Sherlock9. Дивіться його відповідь на алгоритм Python.

function a($n,$k,$q){for($r=($k-1)%$q;$q<$n;$r=($r+$k)%++$q);echo$r+1;}

Як варіант, ось мій оригінальний наївний підхід без алгоритму. Для цього використовується масив для позначення людей, які знайдені.

91 байт

function a($n,$k,$q){for($r=--$i;$q<=$n;++$i%$k||$c[$r]=$q++)while($c[$r=++$r%$n]);echo$r;}

1

Haskell, 48 47 43 байт

(n!k)q=1+foldl(mod.(k+))(mod(k-1)q)[q+1..n]

На основі алгоритму Haskell на сторінці коду Rosetta функції Josephus з двома входами. Пропозиції з гольфу вітаються.

Редагувати: Я дякую німі за допомогу в гольфі першого алгоритму, пропонуючи версію точкової версії, а також за допомогу в гольфі другого алгоритму, повідомляючи мені, що untilключове слово існує.

(n#k)q|m<-k-1=1+n*k-until(>n*m)(\z-> -div(-z*k)m)(q*k-mod m q)

Версія алгоритму в кінці моєї відповіді Python, адаптована з конкретної математики Грема, Кнута та Паташника. Хоча цей алгоритм довший на 62 байти, і його не було так багато, як перший, він швидший для великих nі малих k.

Безголівки:

Перший алгоритм

jos_g num step q = 1 + foldl (\x -> mod (x + step) ) (mod (step-1) q) [q+1..num]

Другий алгоритм

jos_gkp num step q
    -- ceiling throws a type-related fit with ceiling(z*k/(k-1))
    -- better to use - div (-z * k) (k - 1)
    | m <- step-1 = 1 + num*step - until (>num*m)(\z-> -div (-z*k) m) (q*step - mod m q) 

Тож ви вибрали це питання, щоб вивчити нові мови? 6/10 відповідей ваші: П
Мего

@Mego Я згадував про це у чаті: DI запитав, чи варто мені це все-таки опублікувати, і вони сказали, що далі. Також так. Мої друзі сказали мені, що це мій "Привіт, світ!" для нових мов: D
Sherlock9

Я не кажу, що це погано. Мене просто забавляє, ось і все.
Мего

@ Sherlock9: ви можете використовувати untilдля (більш-менш) прямого перекладу версії Python 2 - го алгоритму: (n#k)q|m<-k-1=1+n*k-until(>n*m)(\z-> -div(-z*k)m)(q*k-mod m q).
nimi

Бог тебе, @nimi: Д.І. протягом століть стукав головою над цією проблемою, намагаючись foldlнескінченно перелічити всілякі речі. Спасибі за вашу допомогу!
Шерлок9,

1

GameMaker Language (GML), 88 байт

На основі відповіді @ user81655

r=argument0
k=argument1
q=argument2
r=(k-1)mod q;for(i=q;i<n;r=(r+k)mod ++i){}return r+1

1

Желе , 14 13 байт

Rµṙ⁴ṖµL>⁵µ¿⁴ị

СпробуйтеItOnline!

Як?

Rµṙ⁴ṖµL>⁵µ¿⁴ị - Main link: n, k, q
 µ            - monadic chain separation
R             - range(n): [1,2,3,...,n] - the circle of people
     µ   µ¿   - while
      L       -     length
       >      -     greater than
        ⁵     -     5th program argument (3rd input), i.e. q
  ṙ           -         rotate left by
   ⁴          -         4th program argument (2nd input) i.e. k
    Ṗ         -         pop - remove the rightmost person
            ị - get index
           ⁴  - 4th program argument (2nd input), i.e. k

0

Рубі, 53 48 байт

Лямбда.

->n,k,q{r=(k-1)%q;(q+=1;r=(r+k)%q)while q<n;r+1}

Як це працює

def j(n,k,q)
  r=(k-1)%q   # r starts at j[q,k,q]
  while q<n
    q+=1
    r=(r+k)%q # Every time you add people to the circle, r increases by k, 
              # modulo the current size of the circle q.
  end
  r+1         # Return the result.
end
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.