Числа чистоты

27

Сегодня мы рассмотрим последовательность а , связанную с функцией Коллатца f :

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

Мы называем последовательность вида г, ф (г), F (F (Z)), ... в последовательности Коллатца .

Первое число в нашей последовательности, a (1) , равно 0 . При повторном применении f оно попадает в цикл 0 → 0 →…

Наименьшее число, которое мы еще не видели, равно 1, делая (2) = 1 . При повторном применении f оно попадает в цикл 1 → 4 → 2 → 1 →…

Теперь мы увидели число 2 в цикле выше, поэтому следующим наименьшим числом является (3) = 3 , попадающее в цикл 3 → 10 → 5 → 16 → 8 → 4 → 2 → 1 → 4 → 2 → 1 →…

Во всех вышеперечисленных циклах мы уже видели 4 и 5 , поэтому следующим числом является (4) = 6 .

К настоящему времени вы должны получить идею. a (n) - наименьшее число, которое не входило ни в одну последовательность Коллатца для всех a (1),…, a (n - 1) .

Напишите программу или функцию, которая, учитывая положительное целое число n , возвращает a (n) . Самый короткий код в байтах побеждает.


Testcases:

1  -> 0
2  -> 1
3  -> 3
4  -> 6
5  -> 7
6  -> 9
7  -> 12
8  -> 15
9  -> 18
10 -> 19
50 -> 114

(Это последовательность OEIS A061641 .)

orlp
источник
1
Обязательный OEIS
FryAmTheEggman
3
Может ли ввод nбыть на основе 0?
Луис Мендо
a(n+1) = a(n) odd: 3*a(n)+1, or a(n) even: a(n)/2
Карл Напф
@LuisMendo Извините, я как-то пропустил ваше сообщение. Нет, воспроизведите точную последовательность, как в задании.
orlp
Если aне на основе 0, я не понимаю, почему вы, кажется, здесь говорите «на основе 0»:a(n) is the smallest number that was not part of any Collatz sequences for all a(0), …, a(n − 1).
daniero

Ответы:

5

Желе , 20 19 байтов

ḟ@JḢ×3‘$HḂ?ÐĿ;Ṛ
Ç¡Ṫ

Попробуйте онлайн! или проверьте все тесты .

Как это работает

Ç¡Ṫ              Main link. No explicit arguments. Default argument: 0
 ¡               Read an integer n from STDIN and do the following n times.
Ç                  Call the helper link.
  Ṫ              Tail; extract the last element of the resulting array.


ḟ@JḢ×3‘$HḂ?ÐĿ;Ṛ  Helper link. Argument: A (array)

  J              Yield all 1-based indices of A, i.e., [1, ..., len(A)]. Since 0
                 belongs to A, there is at least one index that does belong to A.
ḟ@               Filter-false swapped; remove all indices that belong to A.
   Ḣ             Head; extract the first index (i) that hasn't been removed.
           ÐĿ    Call the quicklink to the left on i, then until the results are no
                 longer unique. Collect all unique results in an array.
         Ḃ?      If the last bit of the return value (r) is 1:
       $           Apply the monadic 3-link chain to the left to r.
    ×3‘              Yield 3r + 1.
        H        Else, halve r.
              Ṛ  Yield A, reversed.
             ;   Concatenate the results array with reversed A.

После n итераций значение a (n + 1) будет в начале массива. Поскольку мы объединяем новый массив с обращенной копией старого, это означает, что a (n) будет в конце.

Деннис
источник
9

Haskell, 93 92 байта

c x|x<2=[[0,2]!!x]|odd x=x:c(3*x+1)|1<2=x:c(div x 2)
([y|y<-[-1..],all(/=y)$c=<<[0..y-1]]!!)

Пример использования: ([y|y<-[-1..],all(/=y)$c=<<[0..y-1]]!!) 10-> 19.

c xэто цикл Коллатца xс немного изменой x == 1. Основные функции перебирают все целые числа и сохраняют те, которые не предназначены c xдля xin [0..y-1]. Практически прямая реализация определения. Поскольку оператор индекса Haskell !!основан на 0, я начинаю -1с добавления (в противном случае бесполезного) числа, чтобы зафиксировать индекс.

Ними
источник
4

MATL , 46 40 байт

Oiq:"tX>Q:yX-X<`t0)to?3*Q}2/]h5M1>]Pv]0)

Попробуйте онлайн!

объяснение

Код имеет внешний forцикл, который генерирует nпоследовательности Коллатца, по одной в каждой итерации. Каждая последовательность генерируется внутренним do...whileциклом, который вычисляет новые значения и сохраняет их в векторе последовательности до тех пор, пока не будет получено 1или 0. Когда мы закончим с последовательностью, вектор будет инвертирован и объединен с глобальным вектором, который содержит значения из всех предыдущих последовательностей. Этот вектор может содержать повторяющиеся значения. Обращение вектора последовательности гарантирует, что в конце внешнего цикла желаемый результат (начальное значение последней последовательности) будет в конце глобального вектора.

Псевдокод :

1  Initiallization
2  Generate n sequences (for loop):
3    Compute initial value for the k-th sequence
4    Generate the k-th sequence (do...while loop)
5      Starting from latest value so far, apply the Collatz algorithm to get next value
6      Update sequence with new value 
7      Check if we are done. If so, exit loop. We have the k-th sequence
8    Update vector of seen values
9  We now have the n sequences. Get final result

Код комментария :

O           % Push 0                                                          1
iq:         % Input n. Generate [1 2 ... n-1]                                 ·
"           % For loop: repeat n-1 times. Let k denote each iteration         2
  t         %   Duplicate vector of all seen values                           · 3
  X>Q       %   Take maximum, add 1                                           · ·
  :         %   Range from 1 to that: these are potential initial values      · ·
  y         %   Duplicate vector of all seen values                           · ·
  X-X<      %   Set difference, minimum: first value not seen                 · ·
  `         %   Do...while: this generates the k-th Collatz sequence          · 4
    t0)     %     Duplicate, push last value of the sequence so far           · · 5
    to      %     Duplicate, parity: 1 if odd, 0 if even                      · · ·
    ?       %     If odd                                                      · · ·
      3*Q   %       Times 3, plus 1                                           · · ·
    }       %     Else                                                        · · ·
      2/    %       Half                                                      · · ·
    ]       %     End if                                                      · · ·
    h       %     Concatenate new value of the sequence                       · · 6
    5M      %     Push the new value again                                    · · 7
    1>      %     Does it exceed 1? This is the loop condition                · · ·
  ]         %   End do...while. The loops ends when we have reached 0 or 1    · ·
  P         %   Reverse the k-th Collatz sequence                             · 8
  v         %   Concatenate with vector of previously seen values             · ·
]           % End for                                                         ·
0)          % Take last value. Implicitly display.                            9
Луис Мендо
источник
3

Python 2, 97 96 байт

r,=s={-1}
exec'n=r=min({r+1,r+2,r+3}-s)\nwhile{n}-s:s|={n};n=(n/2,3*n+1)[n%2]\n'*input()
print r

Использует тот факт, что все кратные 3 являются чистыми. Проверьте это на Ideone .

Как это работает

В первой строке r,=s={-1}задает s = {-1} (set) и r = -1 .

Затем мы читаем целое число из STDIN, повторяем определенную строку столько раз, а затем выполняем ее. Это эквивалентно следующему коду Python.

for _ in range(input())
    n=r=min({r+1,r+2,r+3}-s)
    while{n}-s:
        s|={n}
        n=(n/2,3*n+1)[n%2]

В каждой итерации мы начинаем с поиска наименьшего члена {r + 1, r + 2, r + 3} , который не принадлежит s . На первой итерации это инициализирует r как 0 .

Во всех последующих запусках s может (и будет) содержать некоторые из r + 1 , r + 2 и r + 3 , но никогда не все из них, поскольку все кратные 3 являются чистыми. Чтобы проверить это утверждение, обратите внимание, что кратное m из 3 не имеет формы 3k + 1 . Это оставляет 2 м как единственно возможное предварительное изображение, которое также кратно 3 . Таким образом, m не может появиться в последовательности Коллатца любого числа, которое меньше, чем m , и поэтому является чистым.

После идентификации r и инициализации n мы применяем функцию Collatz с помощью n=(n/2,3*n+1)[n%2]добавления каждого промежуточного значения n к набору s с помощью s|={n}. Как только мы встретим число n , которое уже находится в s , {n}-sполучим пустое множество, и итерация остановится.

Последнее значение r является желаемым элементом последовательности.

Деннис
источник
1
Чтобы добавить к этому, доказательство того, что все кратные 3 являются чистыми. Посмотрите на любую последовательность Коллатца по модулю 3. После любого применения правила 3x + 1 по модулю равно 1. После применения правила x / 2 мод 1 становится 2, а мод 2 становится 1. Ни одно из правил не может генерировать кратное число. 3, если начальное значение уже не было большим кратным 3, которое было уменьшено вдвое. Но это большие значения, которые еще не генерируются, поэтому n = 0 (mod 3) => n чисто.
orlp
1

Java, 148 байт

int a(int n){if(n<2)return 0;int f=a(n-1),b,i,c;do{f++;for(b=1,i=1;i<n;i++)for(c=i==2?4:a(i);c>1;c=c%2>0?c*3+1:c/2)b=c==f?0:b;}while(b<1);return f;}

Идео это!(Предупреждение: экспоненциальная сложность из-за нулевой оптимизации.)

Преобразование его из do...whileцикла в forцикл было бы лучше, но у меня возникли проблемы с этим.

Совет игры в гольф приветствуется как обычно.

Дрянная Монахиня
источник
Не много, но вы можете сыграть в гольф на 1 байт, изменив for(b=1,i=1;i<n;i++)на for(b=1,i=0;++i<n;). Кстати, я понимаю, почему ваш ideone пропускает тестовый пример для 50, но почему он также пропускает 10? Он может справиться с этим без проблем.
Кевин Круйссен
@KevinCruijssen Потому что форматирование будет плохим.
Утренняя монахиня
Не лучшее улучшение, но я не тратил слишком много времени ... (147 байт)int a(int n){if(n<2)return 0;int f=a(n-1),b=0,i,c;for(;b<1;){f++;for(b=1,i=1;i<n;i++)for(c=i==2?4:a(i);c>1;c=c%2>0?c*3+1:c/2)b=c==f?0:b;}return f;}
Poke
1

Perl6, 96

my @s;my $a=0;map {while ($a=@s[$a]=$a%2??3*$a+1!!$a/2)>1 {};while @s[++$a] {}},2..slurp;$a.say;

На основании ответа Perl 5 . Немного дольше, так как синтаксис Perl6 менее простителен, чем синтаксис Perl5, но на этом я пока остановлюсь.

bb94
источник
0

PHP, 233 124 байта

<?$n=$argv[1];for($c=[];$n--;){for($v=0;in_array($v,$c);)$v++;for(;$n&&!in_array($v,$c);$v=$v&1?3*$v+1:$v/2)$c[]=$v;}echo$v;

+4 для функции:

function a($n){for($c=[];$n--;){for($v=0;in_array($v,$c);)$v++;for(;$n&&!in_array($v,$c);$v=$v&1?3*$v+1:$v/2)$c[]=$v;}return$v;}
Titus
источник
0

Perl 5 - 74 байта

map{0 while 1<($a=$c[$a]=$a%2?$a*3+1:$a/2);0 while$c[++$a]}2..<>;print$a+0

Это довольно простое решение. Он многократно применяет функцию Collatz к переменной $aи сохраняет в массиве, @cчто значение было просмотрено, затем, достигнув 0 или 1, увеличивается $aдо тех пор, пока не увидит число, которое еще не было замечено. Это повторяется количество раз, равное входному значению минус 2, и, наконец, $aвыводится значение.

faubi
источник
0

Mathematica, 134 байта

f=If[EvenQ@#,#/2,3#+1]&;a@n_:=(b={i=c=0};While[i++<n-1,c=First[Range@Max[#+1]~Complement~#&@b];b=b~Union~NestWhileList[f,c,f@#>c&]];c)

Более легкий для чтения формат:

f = If[EvenQ@#, #/2, 3#+1] &;                        Collatz function
a@n_ := (                                            defines a(n)
  b = {i = c = 0};                                   initializations
                                                       b is the growing sequence
                                                       of cycles already completed
  While[i++ < n - 1,                                 computes a(n) recursively
    c = First[Range@Max[# + 1]~Complement~# & @b];   smallest number not in b
    b = b~Union~NestWhileList[f, c, f@# > c &]       apply f to c repeatedly
                                                       until the answer is smaller
                                                       than c, then add this new
                                                       cycle to b
    ]
  ; c)                                                 output final value of c
Грег Мартин
источник