Виведіть n-е раціональне число згідно послідовності Штерна-Брокота


30

Послідовність Штерна-Брокота - це послідовність фібоннаці, яка може бути побудована наступним чином:

  1. Ініціалізуйте послідовність з s(1) = s(2) = 1
  2. Встановити лічильник n = 1
  3. Додайте s(n) + s(n+1)до послідовності
  4. Додайте s(n+1)до послідовності
  5. Зростання n, поверніться до кроку 3

Це еквівалентно:

s (n) = \ початок {випадків} 1 & \ textrm {якщо} n = 1 \ s (\ frac n 2) & \ textrm {if} n \ textrm {рівний} \ s (\ frac {n-1 } 2) + s (\ frac {n + 1} 2) & \ textrm {інакше} \ end {случаи}

Серед інших властивостей послідовність Штерна-Брокота може бути використана для отримання кожного можливого додатного раціонального числа. Кожне раціональне число генерується рівно один раз, і воно завжди з’явиться у найпростіших його словах; наприклад, 1/3є четвертим раціональне число в послідовності, але еквівалентні числа 2/6, і 3/9так далі не будуть з'являтися на всіх.

Ми можемо визначити n-е раціональне число як r(n) = s(n) / s(n+1), де s(n)- n-е число Штерна-Брокота, як описано вище.

Ваше завдання полягає в тому, щоб написати програму або функцію, яка виведе n-е раціональне число, сформоване за допомогою послідовності Штерна-Брокота.

  • Алгоритми, описані вище, є 1-індексованими; якщо ваш запис 0-індексований, будь ласка, вкажіть свою відповідь
  • Описані алгоритми призначені лише для ілюстративних цілей, вихід може бути отриманий будь-яким способом (за винятком жорсткого кодування)
  • Вхід може здійснюватися через STDIN, параметри функції або будь-який інший розумний механізм введення
  • Ouptut може бути STDOUT, консоль, функція повернення значення або будь-який інший розумний вихідний потік
  • Вихід повинен бути у вигляді рядка у формі a/b, де aі bє відповідними записами у послідовності Штерна-Брокота. Оцінка частки до виходу продукції не допустима. Наприклад, для введення 12, вихід повинен бути 2/5, а не 0.4.
  • Стандартні лазівки заборонені

Це , тому найкоротша відповідь у байтах виграє.

Тестові справи

Приклади тестів тут є 1-індексованими.

n    r(n)
--  ------
1    1/1
2    1/2
3    2/1
4    1/3
5    3/2
6    2/3
7    3/1
8    1/4
9    4/3
10   3/5
11   5/2
12   2/5
13   5/3
14   3/4
15   4/1
16   1/5
17   5/4
18   4/7
19   7/3
20   3/8
50   7/12
100  7/19
1000 11/39

Запис OEIS: A002487
Відмінне числофільм, що обговорює послідовність: Нескінченні дроби


Чи може на виході використовувати Trues замість 1s?
Loovjo

1
@Loovjo Ні, True/2не є дійсною фракцією (що стосується мене). З іншого боку, Trueце не завжди 1- деякі мови використовують -1замість цього, щоб уникнути можливих помилок при застосуванні побітових операторів. [цитування потрібно]
Sok



1
@Sok, але в Python, Trueеквівалентно 1і True/2було б 1/2.
Leaky Nun

Відповіді:


3

Желе , 14 байт

3ẋḶŒpḄċ
’Ç”/⁸Ç

Спробуйте в Інтернеті!

О, схоже, я можу перемогти прийняту відповідь від @Dennis, і тією ж мовою. Це працює, використовуючи формулу OEIS: кількість способів вираження (число мінус 1) в гіпербінарному (тобто двійковій з 0, 1, 2 як цифри). На відміну від більшості програм Jelly (які працюють або як повна програма, або як функція), ця працює лише як повноцінна програма (тому що вона відправляє частину виводу в stdout, а решту повертає; при використанні в якості повної програми повертається значення надсилається до stdout неявно, тому весь вихід знаходиться в одному місці, але це не працює для подання функції).

Ця версія програми дуже неефективна. Ви можете створити набагато більш швидку програму, яка працює на весь вхід до 2ⁿ, розмістивши n відразу після першого рядка; програма має O ( n × 3ⁿ) продуктивність, тому збереження n малих тут досить важливо. Програма як написане задає n рівне вхідному, який явно достатньо великий, але також явно занадто великий майже у всіх випадках (але ей, це економить байти).

Пояснення

Як зазвичай у моїх поясненнях Jelly, текст у дужках (наприклад {the input}) показує те, що автоматично заповнюється Jelly через відсутні операнди в початковій програмі.

Функція помічника (обчислює n- й знаменник, тобто n + 1-й чисельник):

3ẋḶŒpḄċ
3ẋ       3, repeated a number of times equal to {the argument}
  Ḷ      Map 3 to [0, 1, 2]
   Œp    Take the cartesian product of that list
     Ḅ   Convert binary (or in this case hyperbinary) to a number
      ċ  Count number of occurrences of {the argument} in the resulting list

Перші п’ять байтів в основному просто генерують всі можливі гіпербінарні числа до заданої довжини, наприклад, з введення 3, вихід становить [[0,1,2], [0,1,2], [0,1,2 ]] таким чином декартовий продукт є [[0,0,0], [0,0,1], [0,0,2], [0,1,0],…, [2,2,1], [2,2,2]]. в основному просто помножує останній запис на 1, передостанній запис на 2, передпопередній запис на 4 тощо, а потім додає; Хоча це зазвичай використовується для перетворення двійкового в десятковий, він може обробляти цифру 2 просто чудово, і, таким чином, працює і для гіпербінарних. Потім ми підраховуємо кількість разів, коли вхід з'являється в отриманому списку, щоб отримати відповідний запис у послідовності. (На щастя, чисельник і знаменник дотримуються тієї ж послідовності).

Основна програма (запитує чисельник та знаменник та форматує вихід):

’Ç”/⁸Ç
’Ç      Helper function (Ç), run on {the input} minus 1 (‘)
  ”/    {Output that to stdout}; start again with the constant '/'
    ⁸Ç  {Output that to stdout}; then run the helper function (Ç) on the input (⁸)

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


Добре горе, ви не жартували, що це неефективно - на TIO 12 потрібно 20 років, а 13 разів повністю! Прийнято, хоча я не можу перевірити всі тестові випадки.
Сік

11

CJam (20 байт)

1_{_@_2$%2*-+}ri*'/\

Інтернет демо . Зауважте, що це 0-індексується. Щоб зробити його індексованим, замініть початковий 1_на T1.

Розсічення

Для цього використовується характеристика, завдяки Моше Ньюману, що

частка a(n+1)/a(n+2)може бути сформована з попереднього дробу a(n)/a(n+1) = xна1/(2*floor(x) + 1 - x)

Якщо x = s/tтоді ми отримаємо

  1 / (2 * floor(s/t) + 1 - s/t)
= t / (2 * t * floor(s/t) + t - s)
= t / (2 * (s - s%t) + t - s)
= t / (s + t - 2 * (s % t))

Тепер, якщо припустити, що це sі tє спільним

  gcd(t, s + t - 2 * (s % t))
= gcd(t, s - 2 * (s % t))
= gcd(t, -(s % t))
= 1

Так a(n+2) = a(n) + a(n+1) - 2 * (a(n) % a(n+1))працює чудово.

1_           e# s=1, t=1
{            e# Loop...
  _@_2$%2*-+ e#   s, t = t, s + t - 2 * (s % t)
}
ri*          e# ...n times
'/\          e# Separate s and t with a /

Любіть методику тут, чудова відповідь!
Сік

Якщо прокрутити далі вниз OEIS, ви побачите, що Майк Стай вже подав цю формулу.
Ніл

11

Haskell, 78 77 65 58 байт

Безсоромно красти оптимізований підхід дає нам:

(s#t)0=show s++'/':show t
(s#t)n=t#(s+t-2*mod s t)$n-1
1#1

Завдяки @nimi для гри в гольф за кілька байтів за допомогою функції інфікування!

(Досі) використовує індексацію на основі 0.


Старий підхід:

s=(!!)(1:1:f 0)
f n=s n+s(n+1):s(n+1):(f$n+1)
r n=show(s n)++'/':(show.s$n+1)

Чорт на вихідний формат ... І оператори індексації. EDIT: І пріоритет.

Веселий факт: якби гетерогенні списки були предметом, останнім рядком може бути:

r n=show>>=[s!!n,'/',s!!(n+1)]

Використання гвардії для прив’язки s!!nповинно бути на один байт коротше:f n|x<-s!!n=x:x+x+1:f$n+1
Laikoni

@Laikoni s!!n+1- ні, (s!!n)+1але s!!(n+1)тому я цього не можу: /
ThreeFx

Дійсно, це мало бути очевидним. Його просто ... стільки s!!nтам!
Лайконі

1
Ви можете використовувати ++'/':(show.s$n+1)в , rщоб зберегти байти.
німі

1
Перемикання на інфіксне: (s#t)0=show..., (s#t)n=t#(s+t-2*mod s t)$n-1, r=1#1. Можна навіть опустити r, тобто останній рядок просто 1#1.
німі

6

Желе , 16 байт

L‘Hị⁸Sṭ
1Ç¡ṫ-j”/

Спробуйте в Інтернеті! або перевірити всі тестові випадки .

Як це працює

1Ç¡ṫ-j”/  Main link. Argument: n

1         Set the return value to 1.
 Ç¡       Apply the helper link n times.
   ṫ-     Tail -1; extract the last two items.
     j”/  Join, separating by a slash.


L‘Hị⁸Sṭ   Helper link. Argument: A (array)

L         Get the length of A.
 ‘        Add 1 to compute the next index.
  H       Halve.
   ị⁸     Retrieve the item(s) of A at those indices.
          If the index in non-integer, ị floors and ceils the index, then retrieves
          the items at both indices.
    S     Compute the sum of the retrieved item(s).
     ṭ    Tack; append the result to A.

5

05AB1E , 34 33 25 23 байт

XX‚¹GÂ2£DO¸s¦ìì¨}R2£'/ý

Пояснення

XX‚                        # push [1,1]
   ¹G           }          # input-1 times do
     Â                     # bifurcate
      2£                   # take first 2 elements of reversed list
        DO¸                # duplicate and sum 1st copy, s(n)+s(n+1)
           s¦              # cut away the first element of 2nd copy, s(n)
             ìì            # prepend both to list
               ¨           # remove last item in list
                 R2£       # reverse and take the first 2 elements
                    '/ý    # format output
                           # implicitly print

Спробуйте в Інтернеті

Збережено 2 байти завдяки Аднану.


Це також працює ?: XX‚¹GÂ2£DO¸s¦ìì¨}R2£'/ý.
Аднан

@Adnan Дійсно. Я забув, що ýможе відформатувати список. Приємно.
Емінья

4

MATL , 20 байт

FT+"@:qtPXnosV47]xhh

Для цього використовується характеристика у вигляді біноміальних коефіцієнтів, наведених на сторінці OEIS .

Алгоритм працює теоретично для всіх чисел, але на практиці він обмежений числовою точністю MATL, і тому він не працює для великих записів. Результат точний для вхідних даних 20щонайменше.

Спробуйте в Інтернеті!

Пояснення

FT+      % Implicitly take input n. Add [0 1] element-wise. Gives [n n+1]
"        % For each k in [n n+1]
  @:q    %   Push range [0 1 ... k-1]
  tP     %   Duplicate and flip: push [k-1 ... 1 0]
  Xn     %   Binomial coefficient, element-wise. Gives an array
  os     %   Number of odd entries in that array
  V      %   Convert from number to string
  47     %   Push 47, which is ASCII for '\'
]        % End for each
x        % Remove second 47
hh       % Concatenate horizontally twice. Automatically transforms 47 into '\'
         % Implicitly display

4

Python 2, 85 81 байт

x,s=input(),[1,1]
for i in range(x):s+=s[i]+s[i+1],s[i+1]
print`s[x-1]`+"/"+`s[x]`

Це подання є 1-індексованим.

За допомогою рекурсивної функції 85 байт:

s=lambda x:int(x<1)or x%2 and s(x/2)or s(-~x/2)+s(~-x/2)
lambda x:`s(x)`+"/"+`s(x+1)`

Якщо вихід подібний True/2прийнятний, ось один із 81 байт:

s=lambda x:x<1 or x%2 and s(x/2)or s(-~x/2)+s(~-x/2)
lambda x:`s(x)`+"/"+`s(x+1)`

3

JavaScript (ES6), 43 байти

f=(i,n=0,d=1)=>i?f(i-1,d,n+d-n%d*2):n+'/'+d

1-індексований; зміна на n=10-індексований. Пов'язана сторінка OEIS має корисне відношення для кожного терміна з точки зору попередніх двох термінів; Я просто переосмислив це як повторення для кожного дробу з точки зору попереднього дробу. На жаль, у нас немає вбудованого TeX, тому вам доведеться просто вставити його на інший сайт, щоб дізнатися, як це формати:

abba+b2(amodb)

3

Python 2, 66 байт

f=lambda n:1/n or f(n/2)+n%2*f(-~n/2)
lambda n:`f(n)`+'/'+`f(n+1)`

Використовується рекурсивна формула.


3

C (GCC), 79 байт

Використовує індексацію на основі 0.

s(n){return!n?:n%2?s(n/2):s(-~n/2)+s(~-n/2);}r(n){printf("%d/%d",s(n),s(n+1));}

Ідеон


1
x?:yє розширенням gcc.
rici

3

Власне, 18 байт

11,`│;a%τ@-+`nk'/j

Спробуйте в Інтернеті!

Це рішення використовує формулу Пітера і аналогічно 0-індексується. Дякуємо Leaky Nun за байт.

Пояснення:

11,`│;a%τ@-+`nk'/j
11                  push 1, 1
  ,`│;a%τ@-+`n      do the following n times (where n is the input):
                      stack: [t s]
    │                 duplicate the entire stack ([t s t s])
     ;                dupe t ([t t s t s])
      a               invert the stack ([s t s t t])
       %              s % t ([s%t s t t])
        τ             multiply by 2 ([2*(s%t) s t t])
         @-           subtract from s ([s-2*(s%t) s t])
           +          add to t ([t+s-2*(s%t) t])
                      in effect, this is s,t = t,s+t-2*(s%t)
              k'/j  push as a list, join with "/"


@LeakyNun Я затримаюсь на цьому вдосконаленні, поки не з’явиться роз'яснення з ОП.
Mego


2

R, 93 байти

f=function(n)ifelse(n<3,1,ifelse(n%%2,f(n/2-1/2)+f(n/2+1/2),f(n/2)))
g=function(n)f(n)/f(n+1)

Буквально найпростіша реалізація. Робота над гольфом трохи.


2

m4, 131 байт

define(s,`ifelse($1,1,1,eval($1%2),0,`s(eval($1/2))',`eval(s(eval(($1-1)/2))+s(eval(($1+1)/2)))')')define(r,`s($1)/s(eval($1+1))')

Визначає такий макрос r, який r(n)оцінюється відповідно до специфікації. Насправді зовсім не гольф, я просто зашифрував формулу.


2

Рубін, 49 байт

Це 0-індексується і використовує формулу Пітера Тейлора. Пропозиції з гольфу вітаються.

->n{s=t=1;n.times{s,t=t,s+t-2*(s%t)};"#{s}/#{t}"}

1

> <> , 34 + 2 = 36 байт

Побачивши відмінну відповідь Пітера Тейлора, я переписав свою тестову відповідь (що бентежило 82 байти, використовуючи дуже незграбну рекурсію).

&01\$n"/"on;
&?!\:@}:{:@+@%2*-&1-:

Він очікує, що вхід буде присутній у стеці, тому +2 байти для -vпрапора. Спробуйте в Інтернеті!


1

Октава, 90 байт

function f(i)S=[1 1];for(j=1:i/2)S=[S S(j)+S(j+1) (j+1)];end;printf("%d/%d",S(i),S(i+1));end

1

C #, 91 90 байт

n=>{Func<int,int>s=_=>_;s=m=>1==m?m:s(m/2)+(0==m%2?0:s(m/2+1));return$"{s(n)}/{s(n+1)}";};

Касти до Func<int, string>. Це рекурсивна реалізація.

Безголовки:

n => 
{
    Func<int,int> s = _ => _; // s needs to be set to use recursively. _=>_ is the same byte count as null and looks cooler.
    s = m =>
        1 == m ? m               // s(1) = 1
        : s(m/2) + (0 == m%2 ? 0 // s(m) = s(m/2) for even
        : s(m/2+1));             // s(m) = s(m/2) + s(m/2+1) for odd
    return $"{s(n)}/{s(n+1)}";
};

Редагувати: -1 байт. Виявляється, C # не потребує пробілу між інтерпольованими рядками returnта $для них.



1

J, 29 байт

([,'/',])&":&([:+/2|]!&i.-)>:

Використання

Великі значення n вимагають суфікса, xякий позначає використання розширених цілих чисел.

   f =: ([,'/',])&":&([:+/2|]!&i.-)>:
   f 1
1/1
   f 10
3/5
   f 50
7/12
   f 100x
7/19
   f 1000x
11/39

100вважається "великим значенням"?
dcsohl

1
@dcsohl У цьому методі обчислюються біноміальні коефіцієнти, а для n = 100 найбільший обчислений - C (72, 28) = 75553695443676829680> 2 ^ 64 і потребуватиме розширених цілих чисел, щоб уникнути значень з плаваючою комою.
милі


Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.