Виведіть 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, тому вам доведеться просто вставити його на інший сайт, щоб дізнатися, як це формати:

ab⇒ba+b−2(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.