H-послідовність Hofstadter


15

Визначення

  • a(0) = 0
  • a(n) = n-a(a(a(n-1))) для цілого числа n > 0

Завдання

Дано невід'ємне ціле число n, виведіть a(n).

Тестові шафи

n     a(n)
0     0
1     1
2     1
3     2
4     3
5     4
6     4
7     5
8     5
9     6
10    7
11    7
12    8
13    9
14    10
15    10
16    11
17    12
18    13
19    13
20    14
10000 6823

Список літератури


Пов’язані виклики щодо послідовностей Хофстадтера: 1 , 2 , 3
Мартін Ендер

4
І я все ще думаю, що вам слід посилатися на GEB ...
Мартін Ендер

1
Як теорія чисел тут актуальна?
недолік

1
@flawr facepalm Дозвольте спробувати ще раз: Гедель, Ешер, Бах: Вічна золота коса
Стиг Хеммер

1
@StigHemmer Насправді facepalm має власну Emoji зараз: 🤦
Tobias Kienzler

Відповіді:


20

Haskell, 23 22 байт

f 0=0
f n=n-f(f$f$n-1)

Просто використовує визначення послідовності. f(f$f$n-1)еквівалентно f (f (f (n-1))).

Тест:

main = putStrLn . show $ map f [0..20]
-- => [0,1,1,2,3,4,4,5,5,6,7,7,8,9,10,10,11,12,13,13,14]

Дякуємо Андерсу Касеоргу за байт!


(f$f$f$n-1)= f(f$f$n-1)зберігає байт.
Anders Kaseorg

9

Желе , 8 байт

’ßßßạµṠ¡

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

Як це працює

’ßßßạµṠ¡  Main link. Argument: n

     µṠ¡  Execute the preceding chain sign(n) times.
’         Decrement n, yielding n - 1.
 ßßß      Recursively call the main link thrice.
    ạ     Take the absolute difference of n and the result.

9
Чи може аналізатор Jelly навіть обробляти програми розміром більше 10 байт?
steenbergh

9

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

Кількість байтів передбачає кодування ISO 8859-1 (або сумісного) і $CharacterEncodingвстановлюється на відповідне значення, як у Windows за замовчуванням WindowsANSI.

±0=0
±n_:=n-±±±(n-1)

Це визначає одинарний оператор ±.


Ви б пояснили, що ± робить або як працює? Btw, вітаємо на 100 к.
DavidC

1
@DavidC Дякую :) Це просто вбудований оператор, який є скороченим для невикористаної функції PlusMinus. Детальніше дивіться у цій публікації .
Мартін Ендер

1
Дуже цікаво. Диспетчери з @або [ ]занадто.
DavidC

9

J, 14 12 байт

-$:^:3@<:^:*

Збережено 2 байти завдяки @ Leaky Nun .

Обчислює результат, викликаючи себе рекурсивно, коли n > 0 тричі n -1, і віднімаючи цей результат від n . Існує інша ситуація для базового випадку, коли n = 0. Там він обчислює n - n, що дорівнює 0.

a(n) = n - n = 0           if n = 0
       n - a(a(a(n-1)))    if n > 0

Спробуйте тут.

Пояснення

-$:^:3@<:^:*  Input: n
           *  Get the sign of n (n = 0 => 0, n > 0 => 1)
         ^:   Execute that many times
                (0 times means it will just be an identity function)
       <:       Decrement n
 $:             Call itself recursively
   ^:3          three times
      @         on n-1
-             Subtract that result from n and return

Я не думаю, що дужки потрібні.
Leaky Nun

6

Джулія, 16 байт

!n=n>0&&n-!!!~-n

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

Як це працює

Ми переосмислюємо одинарний оператор ! для наших цілей.

Якщо n = 0 , порівняння n>0повертає помилкове значення !.

В іншому випадку код після &&його виконання. ~-nеквівалентний (n-1)комплементу двох, !!!рекурсивно викликає !тричі на n - 1 , і отримане значення віднімається від n .


Розум додає пояснення? Я поняття не маю, що відбувається з -!!~-._.
Пуховик

1
Нічого фантазійного. !це просто ім'я функції.
Денніс

5

Пітон, 31 байт

a=lambda n:n and n-a(a(a(n-1)))

Межа рекурсії та обмеження часу роблять вищезгадану функцію недоцільною, але теоретично вона повинна працювати (і працює для малих n).


4

JavaScript (ES6), 52 байти

n=>[0,...Array(n)].reduce((p,_,i,a)=>a[i]=i-a[a[p]])

Я міг би бути нудним і написав рекурсивну версію, але ця версія набагато швидша (легко справляється з останнім тестовим випадком), а також використовує, reduceтак що це плюс!




3

R, 42 41 байт

a=function(n)ifelse(n<1,0,n-a(a(a(n-1))))

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

> a(1)
1
> a(10)
7

Цей рекурсивний підхід не підходить для великих значень, nхоча.


Ви повинні мати можливість втратити байт (і ряд помилок без поганих входів), якщо ви змінили свою умову на n<1. Як свою послідовність, вона дійсно визначається лише для негативних цілих чисел.
користувач5957401

a=function(n)"if"(n,n-a(a(a(n-1))),0)буде працювати на кілька байтів.
Джузеппе


2

Сесо , 58 55 байт

0000000: 16e0d7 bdcdf8 8cdf1b e6cfbb 840d3f bf659b 38e187  ..............?.e.8..
0000015: f8639b 39dc37 fc893f 666c05 7e7ed9 b88b3f ae0d3f  .c.9.7..?fl.~~...?..?
000002a: 676ed8 bd9940 7fdc3b 36619e f1                    gn...@..;6a..

Робота з входами до 400 досить добре, але час роботи різко збільшується після цього.

Спробуйте в Інтернеті! Перевірте налагодження, щоб побачити створений код SBIN.

Збірка Sesos

Бінарний файл, створений вище, був сформований шляхом складання наступного коду SASM.

set numin, set numout

get
jmp
    jmp
        rwd 3, add 1, rwd 1, add 1, fwd 4, sub 1
    jnz
    rwd 3, sub 1
jnz
rwd 3, add 1, fwd 2
jmp
    rwd 1, sub 1, fwd 3, sub 1, fwd 2, add 3
    jmp
        rwd 2
        jmp
            rwd 3
        jnz
        fwd 6, get, rwd 4, sub 1
        jmp
            fwd 1, sub 1
            jmp
                rwd 3
            jnz
            sub 1
            jmp
                fwd 3
            jnz
            rwd 4, sub 1
        jnz
        fwd 1
        jmp
            rwd 1, add 1, fwd 1, add 1
        jnz
        sub 1, fwd 3, sub 1
        jmp
            fwd 3
        jnz
        rwd 1, sub 1
    jnz
    rwd 2, get
    nop
        rwd 3
    jnz
    fwd 3, get, rwd 2
    jmp
        fwd 2, add 1
        jmp
            fwd 3
        jnz
        rwd 1, add 1, rwd 2
        jmp
            rwd 3
        jnz
        fwd 1, sub 1
    jnz
    fwd 2
    jmp
        rwd 2, add 1, fwd 2, sub 1
    jnz
    nop
        get, fwd 3
    jnz
    rwd 1, add 1, fwd 2
jnz
rwd 2, sub 1
jmp
    rwd 1, sub 1, fwd 1, sub 1
jnz
rwd 1, put

2

LISP, 61 байт

(defun H(N)(if(= N 0)(return-from H 0)(- N(H(H(H(- N 1)))))))

Напевно, не оптимальне рішення, але воно працює.


1

Java 7, 42 байти

int c(int n){return n>0?n-c(c(c(n-1))):0;}

Невикористані та тестові справи:

Спробуйте тут.

class Main{
  static int c(int n){
    return n > 0
              ? n - c(c(c(n-1)))
              : 0;
  }

  public static void main(String[] a){
    for(int i = 0; i < 21; i++){
      System.out.println(i + ": " + c(i));
    }
    System.out.println("1000: " + c(1000));
  }
}

Вихід:

0: 0
1: 1
2: 1
3: 2
4: 3
5: 4
6: 4
7: 5
8: 5
9: 6
10: 7
11: 7
12: 8
13: 9
14: 10
15: 10
16: 11
17: 12
18: 13
19: 13
20: 14
 (last case takes too long..)

1

Рубін, 27 байт

Очевидна реалізація.

a=->n{n<1?0:n-a[a[a[n-1]]]}

Це довша, швидша відповідь, яка кешує попередні записи в послідовності. Обидві відповіді працюють лише для версій після 1.9, як це було тоді ->, коли старі лямбда були представлені Ruby.

->n{r=[0];i=0;(i+=1;r<<i-r[r[r[i-1]]])while i<n;r[n]}



1

C, 35 32 байти

Збережено 3 байти завдяки @PeterTaylor!

a(n){return n?n-a(a(a(n-1))):0;}

Спробуйте це на Ideone!


2
У C ви можете використовувати ціле число безпосередньо як умовне, даючи трибайтове збереження:a(n){return n?n-a(a(a(n-1))):0;}
Пітер Тейлор

1
@betseg - У вас також є помилка :в коді. Ви повинні вийняти той після ?.
owacoder

1

Javascript ES6, 22 байти

a=n=>n&&n-a(a(a(n-1)))

Мені буде нудно і робитиму рекурсивну версію: P


1

VBA, 69 байт

Function H(N):ReDim G(N):For j=1To N:G(j)=j-G(G(G(j-1))):Next:H=G(N)

Працює за мить очей на тестовому наборі, сповільнюється трохи вище n = 1000000, впадає в стіну пам'яті трохи вище n = 25 мільйонів.


1

Pyth, 10 байт

L-WbbyFtb3

Визначає функцію y. Спробуйте в Інтернеті: Демонстрація

Тут використовується відносно нова особливість Pyth. Ви можете застосувати функцію кілька разів, використовуючи синтаксис fold. Він насправді не зберігає жодних байтів, я використовував його лише для демонстраційних цілей.

Пояснення:

L-WbbyFtb3
L            define function y(b), that returns:
    b           b
 -Wb            and subtract the following if b>0
     yF  3      y applied three times to
       tb       b - 1

1

Клен, 28 26 байт

`if`(n=0,0,n-a(a(a(n-1))))

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

> a:=n->ifelse(n=0,0,n-a(a(a(n-1))));
> seq(a(i),i=0..10);
0, 1, 1, 2, 3, 4, 4, 5, 5, 6, 7

1

постійного струму, 34 байти

dsn[zdddd1-;a;a;a-r:aln!=L]dsLx;ap

Введення береться з верхньої частини стека. Це має бути єдиним елементом у стеці, оскільки глибина стека використовується як лічильник. Приклад використання:

$ dc
10000dsn[zdddd1-;a;a;a-r:aln!=L]dsLx;ap

Це досить просто реалізація визначення послідовності:

dsn               # Store n as `n', and keep a copy as a depth buffer (see below)
[                 # Open loop definition
 z                # Push stack depth i for i-th term
 dddd             # Duplicate stack depth four times, for a total of five copies
 1-               # Get i-1 for use as index to previous term
                  #   Note that if we hadn't duplicated n above, or left something else
                  #   on the stack, 0-1 would be -1, which is not a valid array index
 ;a;a;a           # Fetch a(a(a(i-1)))
 -                # Calculate i-a(a(a(i-1)))
 r                # Arrange stack to store i-th term: TOS |  i  (i-a(a(a(i-1))))
 :a               # Store i-th term in array `a'
 ln!=L            # Load n. If n!=i, we're not done calculating terms yet, so execute loop
]                 # Close loop definition. Note that we started with five copies of i:
                  #   i-1 was used to get last term
                  #   i-a(...) was used to calculate current term
                  #   ... i :a was used to store current term
                  #   i ln !=L was used to check loop exit condition
                  # One copy of i is left on the stack to increment counter
dsLx              # Duplicate loop macro, store it, and execute copy
;a                # Last i stored on stack from loop will equal n, so use this to get a(n)
p                 # Print a(n)

У будь-якому випадку, це почалося прямо ... тоді сталося гольф.



1

C ++ (в основному MSVC)

Нормальна версія: 40 байт

int a(int n){return n?n-a(a(a(n-1))):0;}

Версія мета програмування шаблону: 130 байт

#define C {constexpr static int a(){return
template<int N>struct H C N-H<H<H<N-1>::a()>::a()>::a();}};template<>struct H<0>C 0;}};

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

std::cout << a(20) << '\n';       // Normal version
std::cout << H<20>::a() << '\n';  // Template version

Версія шаблону - це найшвидший код, оскільки немає нічого швидшого, ніж переміщення значення в регістр => з оптимізацією, H<20>::a()компілюйте як:

mov esi, 14

Для 10000 рекурсивна версія виходить з ладу через помилку переповнення стека, а версія шаблону виходить з ладу під час компіляції через глибину інстанціалізації шаблону. GCC переходить до 900 (614)


Думаю, вам не потрібно місця між Cі {у версії метапрограмування шаблону
Zacharý

@ Zacharý MSVC відмовляється компілювати без цього місця
HatsuPointerKun

Ага, я бачу, чому це, здається, продовжує відбуватися
Zacharý

@ Zacharý Це залежить від типу макросу. Якщо у нього є параметри, то я можу видалити пробіл, але тут цього немає
HatsuPointerKun




0

PowerShell v2 +, 56 байт

$a={$n=$args[0];if($n){$n-(&$a(&$a(&$a($n-1))))}else{0}}

Еквівалент PowerShell лямбда утворює рекурсивне визначення. Виконайте це через &оператора виклику, наприклад &$a(5). Займає довго часу - навіть50 на моїй машині (недавній i5 з 8 ГБ оперативної пам’яті) потрібно близько 90 секунд.

Швидше ітеративне рішення, 59 байт

param($n)$o=,0;1..$n|%{$o+=$_-$o[$o[$o[$_-1]]]};$o[-1]*!!$n

Більш довгий лише тому, що нам потрібно враховувати вхід 0(це *!!$nв кінці). В іншому випадку ми просто ітеративно побудуємо масив до $n, кожен раз додаючи новий елемент і виводячи останній в кінці $o[-1]. Супершвидкісний - обчислення 10000на моїй машині займає близько 5 секунд.


0

> <> , 55 + 2 = 57 байт

^~n;
.~-]{:0$
v>1-}32[
v/  /:1-32[
>$:?/$~]{:0$.
/30@2[

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

Це хека повільно, оскільки для обчислення результату використовується рекурсія. Використання TIO h(50)займає більше хвилини. Він повертає правильні результати <= 30, тому я впевнений, що це спрацювало б h(10000), я просто не запустив це, щоб дізнатися!

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