Знайти всі виразні мережі Гозінта


36

Ланцюги Гозінта

(Натхненний проектом Euler # 606 )

Ланцюг gozinta для n - це послідовність, {1,a,b,...,n}де кожен елемент належним чином ділить наступний. Наприклад, існує вісім різних ланцюжків гозінти на 12:

{1,12}, {1,2,12}, {1,2,4,12}, {1,2,6,12}, {1,3,12}, {1,3,6,12}, {1,4,12} and {1,6,12}.

Змагання

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

  1. Порядок у ланцюгах має значення (висхідний), порядок ланцюгів не робить.
  2. За випадкового випадку, що ви не можете використовувати вбудований, який вирішує проблему.
  3. Це .

Редагувати: Видалення 1як потенційний вхід.


4
Ласкаво просимо до PPCG. Приємне перше запитання!
AdmBorkBork

5
"На випадковий випадок він існує [(дивлячись на вас, Mathematica!)]"
Ерік Вигнавець

3
За словами AdmBorkBork, крайові випадки , як правило , додають тільки якщо вони мають важливе значення для ядра виклик - якщо ви хочете причину тільки [[1]]я б сказав , що якщо [1,1]це gozinta з 1то [1,1,12]є gozinta з 12як [1,1,1,12]і тепер ми можемо більше не "повертай усіх ..."
Джонатан Аллан

4
Ви повинні чітко визначити каламбур у питанні для тих, хто цього не знає. 2|4читається "два переходить у чотири", "ще" два гозінта чотири ".
mbomb007

1
Дві з половиною години - це недостатньо часу для роботи пісочниці. Дивіться поширені питання щодо пісочниці .
Пітер Тейлор

Відповіді:


10

Python 3 , 68 65 байт

Редагувати: -3 байти завдяки @notjagan

f=lambda x:[y+[x]for k in range(1,x)if x%k<1for y in f(k)]or[[x]]

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

Пояснення

Кожна ланцюжок гозінта складається з числа xв кінці ланцюга, принаймні один дільник зліва від неї. Для кожного дільника kз xланцюгів [1,...,k,x]різні. Таким чином , ми можемо для кожного дільника kзнайти всі його різні gozinta ланцюгів і приєднувати xдо кінця них, щоб отримати всю різну gozinta ланцюг з kбезпосередньо зліва x. Це робиться рекурсивно до x = 1тих пір, куди [[1]]не повернеться, оскільки всі ланцюги гозінти починаються з 1, тобто рекурсія знизилася вниз .

Код стає таким коротким через розуміння списку Python, що дозволяє подвійну ітерацію. Це означає, що знайдені значення f(k)можуть бути додані до одного списку для всіх різних дільників k.


намагався це зробити, зараз занадто пізно = /
Род

3
Ця відповідь неймовірно швидка порівняно з іншими поки що.
ajc2000

-3 байти , видаливши непотрібний список, розпаковуючи.
notjagan

7

Лушпиння , 13 байт

ufo=ḣ⁰…ġ¦ΣṖḣ⁰

Дещо інший підхід до H.PWiz , хоча ще й грубою силою. Спробуйте в Інтернеті!

Пояснення

Основна ідея полягає в об'єднанні всіх підрядів [1,...,n]і розподілі результату на підспіси, де кожен елемент ділить наступний. З них ми зберігаємо ті, що починаються 1, закінчуються nі не містять дублікатів. Це робиться за допомогою вбудованого "рангіфікувати" . Тоді залишається відкинути дублікати.

ufo=ḣ⁰…ġ¦ΣṖḣ⁰  Input is n=12.
           ḣ⁰  Range from 1: [1,2,..,12]
          Ṗ    Powerset: [[],[1],[2],[1,2],[3],..,[1,2,..,12]]
         Σ     Concatenate: [1,2,1,2,3,..,1,2,..,12]
       ġ¦      Split into slices where each number divides next: [[1,2],[1,2],[3],..,[12]]
 fo            Filter by
      …        rangified
   =ḣ⁰         equals [1,...,n].
u              Remove duplicates.

Я здогадуюсь, що фільтрувати до масивів в наборі потужності не менше, де кожне число ділить наступне?
ETHproductions

@ETHproductions Ні, це на один байт довше .
Згарб

5

Желе , 9 8 байт

ÆḌ߀Ẏ;€ȯ

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

Використовує подібну методику до моєї відповіді Japt , і тому працює дуже швидко на великих тестових кейсах .

Як це працює

ÆḌ߀Ẏ;€ȯ    Main link. Argument: n (integer)
ÆḌ          Yield the proper divisors of n.
       ȯ    If there are no divisors, return n. Only happens when n is 1.
  ߀        Otherwise, run each divisor through this link again. Yields
            a list of lists of Gozinta chains.
    Ẏ       Tighten; bring each chain into the main list.
     ;€     Append n to each chain.

4

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

FindPath[Graph@Cases[Divisors@#~Subsets~{2},{m_,n_}/;m∣n:>m->n],1,#,#,All]&

Формує a, Graphде вершини є Divisorsвхідними #, а ребра представляють належну подільність, потім знаходять Allшляхи від вершини 1до вершини #.


1
Вау, це досить розумно!
JungHwan Min

3

Желе , 12 байт

ŒPµḍ2\×ISµÐṀ

Монадічне посилання, що приймає ціле число і повертає список списків цілих чисел.

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

Як?

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

ŒPµḍ2\×ISµÐṀ - Link: number N
ŒP           - power-set (implicit range of input) = [[1],[2],...,[N],[1,2],[1,3],...,[1,N],[1,2,3],...]
          ÐṀ - filter keep those for which the result of the link to the left is maximal:
  µ      µ   - (a monadic chain)
    2\       -   pairwise overlapping reduce with:
   ḍ         -     divides? (1 if so, 0 otherwise)
       I     -   increments  e.g. for [1,2,4,12] -> [2-1,4-2,12-4] = [1,2,8]
      ×      -   multiply (vectorises) (no effect if all divide,
             -                          otherwise at least one gets set to 0)
        S    -   sum         e.g. for [1,2,4,12] -> 1+2+8 = 11 (=12-1)

Зачекайте, що зменшиться n-розумне перекриття? : o як я ніколи цього не бачив: PI використовував <slice>2<divisible>\<each>: P
HyperNeutrino

Використовуючи останню зміну клейкі Jelly, ви можете використовувати Ɲзамість `2` на 11 байт .
Містер Xcoder

3

Japt , 17 байт

⬣ßX m+S+UR÷ª'1

Перевірте це в Інтернеті!

Дивно, генерувати висновок як рядок було набагато простіше, ніж генерувати його як масив масивів ...

Пояснення

 ⬠£  ßX m+S+URà ·  ª '1
Uâq mX{ßX m+S+UR} qR ||'1   Ungolfed
                            Implicit: U = input number, R = newline, S = space
Uâ                          Find all divisors of U,
  q                           leaving out U itself.
    mX{         }           Map each divisor X to
       ßX                     The divisor chains of X (literally "run the program on X")
          m    R              with each chain mapped to
           +S+U                 the chain, plus a space, plus U.
                  qR        Join on newlines.
                     ||     If the result is empty (only happens when there are no factors, i.e. U == 1)
                       '1     return the string "1".
                            Otherwise, return the generated string.
                            Implicit: output result of last expression

Тож чи уникає ваш підхід генерувати недійсні ланцюги, а потім фільтрувати їх, як це роблять інші підходи?
Парасолька

@ Umbrella Nope, він генерує лише дійсні, по одному дільнику, і тому він працює блискавично навіть у таких випадках, як 12000 :-)
ETHproductions

Дуже приємно використовувати рекурсію :) І я трюкую цей ¬трюк! : p
Shaggy

@Shaggy ¬є однією з причин, чому я реалізував купу функцій, які в основному "роблять X без аргументів, або Y дають truthy аргумент": P
ETHproductions

3

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

Cases[Subsets@Divisors@#,x:{1,___,#}/;Divisible@@Reverse@{x}]&

Використання недокументованих мульти-Arg форми Divisible, де Divisible[n1,n2,...]повертається , Trueякщо n2∣n1, n3∣n2і так далі, і в Falseіншому випадку. Ми беремо весь Subsetsсписок Divisorsвхідних даних #, а потім повертаємо Casesформу {1,___,#}такої, яка Divisibleдає Trueдля Reversed послідовність дільників.


Отже, чи Divisibleє в основному вбудований елемент для перевірки ланцюга гозінти?
Парасолька

@Umbrella Це не перевіряє належну подільність.
ngenisis

3

Haskell, 51 байт

f 1=[[1]]
f n=[g++[n]|k<-[1..n-1],n`mod`k<1,g<-f k]

Рекурсивно знайдіть ланцюги гозінти належних дільників і додайте їх n.

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


Я вважаю, що для належного поводження з ними потрібно мати додатковий кредит 1. Оскільки ми колективно дійшли висновку про звільнення 1, чи можете ви зберегти 10 байт, видаливши цю справу?
Парасолька

@ Umbrella 1не є окремим випадком для цього алгоритму, він потрібен як базовий випадок для рекурсії. Само по собі друге визначальне рівняння може повернути лише порожній список.
Крістіан Сіверс

Розумію. Моє рішення (поки що не опубліковано) також використовує [[1]]як базу.
Парасолька

3

Haskell (Lambdabot), 92 85 байт

x#y|x==y=[[x]]|1>0=(guard(mod x y<1)>>(y:).map(y*)<$>div x y#2)++x#(y+1)
map(1:).(#2)

Потрібен Lambdabot Haskell, оскільки його guardпотрібно Control.Monadімпортувати. Основна функція - це анонімна функція, яка, як мені кажуть, дозволена, і вона обробляє пару байтів.

Дякуємо Лайконі за збереження семи байтів.

Пояснення:

Монади дуже зручні.

x # y

Це наша рекурсивна функція, яка виконує всю фактичну роботу. x- це число, яке ми накопичуємо (добуток дільників, які залишаються у значенні), і yце наступне число, яке ми повинні спробувати поділити на нього.

 | x == y = [[x]]

Якщо xдорівнює, yто ми закінчуємо повторення. Просто використовуйте xяк кінець поточного ланцюжка gozinta і поверніть його.

 | 1 > 0 =

Haskell golf-ism для "Правда". Тобто це справа за замовчуванням.

(guard (mod x y < 1) >>

Зараз ми працюємо всередині монади у списку. У монаді списку ми маємо можливість робити кілька варіантів одночасно. Це дуже корисно, коли вичерпавши «все можливе» чогось. У guardзаяві сказано: "Розгляньте наступний вибір лише тоді, коли умова справжня". У цьому випадку враховуйте наступний вибір лише у випадку yрозділення x.

(y:) . map (y *) <$> div x y#2)

Якщо yрозділимо x, ми маємо вибір додати yдо ланцюжка гозінта. У цьому випадку рекурсивно дзвоніть (#), починаючи y = 2з рівня, xрівного x / yтому, що ми хочемо "визначити", що yтільки що додали до ланцюга. Тоді, незалежно від результату цього рекурсивного виклику, множимо його значення на yщойно розроблені нами дані та додаємо yдо ланцюгу gozinta офіційно.

++

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

x # (y + 1)

Інший варіант - просто продовжувати повторення та не використовувати значення y. Якщо yне ділиться, xто це єдиний варіант. Якщо yрозділити, xто цей варіант буде прийнятий, як і інший варіант, і результати будуть об'єднані.

map (1 :) . (# 2)

Це основна функція гозінта. Починається рекурсія з виклику (#)своїм аргументом. A 1є попередньою для кожного ланцюга gozinta, оскільки (#)функція ніколи не ставить їх у ланцюги.


1
Чудове пояснення! Ви можете зберегти кілька байтів, поставивши всі шаблони шаблонів в один рядок. mod x y==0можна скоротити до mod x y<1. Оскільки анонімні функції дозволені, ваша основна функція може бути записана як безвідмовна map(1:).(#2).
Лайконі

3

Хаскелл, 107 100 95 байт

f n=until(all(<2).map head)(>>=h)[[n]]
h l@(x:_)|x<2=[l]|1<2=map(:l)$filter((<1).mod x)[1..x-1]

Можливо, є краща умова припинення (спробував щось подібне

f n=i[[n]]
i x|g x==x=x|1<2=i$g x
g=(>>=h)

але це довше). Перевірка на 1предмет здається розсудливою, як миючий повтор1 або дублікатів ( nubне в Prelude) більше байтів.

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


3
(>>=h)за(concatMap h)
Майкл Кляйн


Святе лайно я дурний про u...
Лейф Віллерс

3

JavaScript (Firefox 30-57), 73 байти

f=n=>n>1?[for(i of Array(n).keys())if(n%i<1)for(j of f(i))[...j,n]]:[[1]]

Зручно n%0<1помилково.


2

Желе , 17 байт

ḊṖŒP1ppWF€ḍ2\Ạ$Ðf

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


Це було вражаюче швидко. 1Однак ваш результат несподіваний Мені не вдалося знайти остаточного результату 1, але я припустив, що він є [[1]]. Я не можу сказати точно, що [1,1]це неправильно, за винятком того, що всі інші результати збільшують послідовність. Думки?
Парасолька

@Umbrella Ви можете дозволити відповідям робити що-небудь за 1.
Містер Xcoder

@ Umbrella Якщо це проблема, я можу виправити її за +2 (замінити ;€на ;Q¥€).
Erik the Outgolfer

2

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

(S=Select)[Rest@S[Subsets@Divisors[t=#],FreeQ[#∣#2&@@@Partition[#,2,1],1>2]&],First@#==1&&Last@#==t&]&

FreeQ[...]може статиAnd@@BlockMap[#∣#2&@@#&,#,2,1]
JungHwan Min

дуже хороша! але я отримую додаткове повідомлення DeveloperPartitionMap :: nlen: - Текст повідомлення не знайдено - >> `чому це?
J42161217

BlockMapвикористовує Developer`PartitionMapфункцію внутрішньо, але оскільки це функція розробника, вона не має повідомлень про помилки. Помилка викликана списками, які містять 1 або 0 елементів, з якими ви не можете зробити 2-розділи.
JungHwan Min

2

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

Cases[Subsets@Divisors@#,{1,___,#}?(And@@BlockMap[#∣#2&@@#&,#,2,1]&)]&

Пояснення

Divisors@#

Знайдіть усі дільники вводу.

Subsets@ ...

Створити всі підмножини цього списку.

Cases[ ... ]

Виберіть усі випадки, які відповідають шаблону ...

{1,___,#}

Починаючи з 1 і закінчуючи <input>...

?( ... )

і відповідає умові ...

And@@BlockMap[#∣#2&@@#&,#,2,1]&

Лівий елемент ділить правий елемент для всіх 2-х розділів списку, зміщених 1.


2

TI-BASIC, 76 байт

Input N
1→L1(1
Repeat Ans=2
While Ans<N
2Ans→L1(1+dim(L1
End
If Ans=N:Disp L1
dim(L1)-1→dim(L1
L1(Ans)+L1(Ans-(Ans>1→L1(Ans
End

Пояснення

Input N                       Prompt user for N.
1→L1(1                        Initialize L1 to {1}, and also set Ans to 1.

Repeat Ans=2                  Loop until Ans is 2.
                              At this point in the loop, Ans holds the
                              last element of L1.

While Ans<N                   While the last element is less than N,
2Ans→L1(1+dim(L1              extend the list with twice that value.
End

If Ans=N:Disp L1              If the last element is N, display the list.

dim(L1)-1→dim(L1              Remove the last element, and place the new
                              list size in Ans.

L1(Ans)+L1(Ans-(Ans>1→L1(Ans  Add the second-to-last element to the last
                              element, thereby advancing to the next
                              multiple of the second-to-last element.
                              Avoid erroring when only one element remains
                              by adding the last element to itself.

End                           When the 1 is added to itself, stop looping.

Я міг би зберегти ще 5 байт, якщо дозволено вийти з помилкою, а не витончено, видаливши чек Ans> 1 та стан циклу. Але я не впевнений, що це дозволено.


Ви ввели це у свій калькулятор? Бо це несподівано і дещо вражає.
Парасолька

Так! Хитра частина TI-BASIC полягає в тому, що існують лише глобальні змінні, тому мені довелося ефективно використовувати сам список як мій стек рекурсії.
calc84maniac

2

Mathematica 86 77 байт

Select[Subsets@Divisors@#~Cases~{1,___,#},And@@BlockMap[#∣#2&@@#&,#,2,1]&]&

Груба сила за визначенням.

Бажаючи, був коротший спосіб провести парне послідовне порівняння елементів списку.

Дякуємо @Jenny_mathy та @JungHwanMin за пропозиції, економлячи 9 байт


1
ви можете використовувати FreeQ[#∣#2&@@@Partition[#,2,1],1>2]&](як другий аргумент), щоб перейти до 82 байт
J42161217

@Jenny_mathy Або краще,And@@BlockMap[#∣#2&@@#&,#,2,1]
JungHwan Min

1

Лушпиння , 17 16 байт

-1 байт, завдяки Згарбу

foEẊ¦m`Je1⁰Ṗthḣ⁰

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


Короткий, але повільний. Я поставив 50вхід і він вийшов. У чому полягає суть вашого підходу?
Парасолька

По суті, він намагається
виконати

@ Umbrella TIO має 60-секундний тайм-аут, це не вина програми.
Ерік Аутгольфер

o`:⁰:1можна`Je1⁰
Згарб

@Zgarb Ще раз ...
H.PWiz

0

PHP 147 141

Відредаговано, щоб видалити зайвий тест

function g($i){$r=[[1]];for($j=2;$j<=$i;$j++)foreach($r as$c)if($j%end($c)<1&&$c[]=$j)$r[]=$c;foreach($r as$c)end($c)<$i?0:$R[]=$c;return$R;}

Пояснили:

function g($i) {

15 символів котла :(

    $r = [[1]];

Запустіть результат, встановлений так, [[1]]як кожен ланцюг починається з 1. Це також призводить до підтримки 1 як входу.

    for ($j = 2; $j <= $i; $j++) {
        foreach ($r as $c) {
            if ($j % end($c) < 1) {
                $c[] = $j;
                $r[] = $c;
            }
        }
    }

Для кожного числа від 2 до $i, ми будемо продовжувати кожну ланцюжок у нашому наборі на поточне число, якщо воно gozinta , тоді додамо розширений ланцюг до нашого набору результатів.

    foreach ($r as $c) {
        end($c) < $i ? 0 : $R[] = $c;
    }

Відфільтруйте наші проміжні ланцюги, до яких не вдалося $i

    return $R;
}

10 символів котла :(


-1

Математика

f[1] = {{1}};
f[n_] := f[n] = Append[n] /@ Apply[Join, Map[f, Most@Divisors@n]]

Відповідь кешується на додаткові дзвінки.


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