Кількість циклів перестановки


23

Розглянемо перестановку цілих чисел 1, ... n, таких як ця для n = 6:

[5,2,4,3,6,1]

Якщо ви розглядаєте перестановку як відображення від [1,2,3,4,5,6]до [5,2,4,3,6,1], перестановку можна розкласти на непересічні цикли . Цикл - це підмножина елементів, які зіставляються один з одним. Наприклад, 1отримує картографування 5, яке отримує відображення 6, яке повертається до нього 1. Отже один цикл є [1,5,6]. Інші цикли - це [2]і [3,4]. Таким чином, кількість циклів для цієї перестановки становить 3.

Взагалі, цикли перестановки є унікальними (на замовлення), а кількість циклів перестановки розмірів nзмінюється від 1- n.

Змагання

Враховуючи не порожню перестановку, виведіть її кількість циклів.

Вхідний масив , утворений nцілих чисел 1, 2, ..., n, де n > 0. Кожне ціле число відбувається рівно один раз. Порядок, в якому вони з'являються, визначає перестановку, як у наведеному вище прикладі.

Замість масиву можна використовувати список, рядок з роздільником між номерами, окремий ввід для кожного номера або все, що є розумним.

Для перестановки розміру nзамість 1 -го набору цілих чисел 1, ..., nви можете послідовно використовувати набір на основі 0 0, ..., n-1. Якщо так, то просимо вказати це у своїй відповіді.

Код повинен працювати nдо 20розумного часу, скажімо, менше однієї хвилини.

Код гольфу. Всі вбудовані дозволені.

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

Це передбачає введення масиву на основі 1.

 [1] -> 1
 [3,2,1] -> 2
 [2,3,4,5,1] -> 1
 [5,2,4,3,6,1] -> 3
 [8,6,4,5,2,1,7,3] -> 2
 [4,5,11,12,7,1,3,9,10,6,8,2] -> 1
 [4,2,5,11,12,7,1,3,9,10,6,8] -> 5
 [5,8,6,18,16,9,14,10,11,12,4,20,15,19,2,17,1,13,7,3] -> 3
 [14,5,17,15,10,18,1,3,4,13,11,16,2,12,9,7,20,6,19,8] -> 7

Пов'язані

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


Не зважаючи на моє запитання, це вказано в запитанні на основі дозволу 0.
orlp

@orlp Це було швидко! Я навіть не побачив вашого запитання
Луїс Мендо

Чи можна взяти відображення індексів до значень як вхідних даних?
Мідь

1
@Copper Я думаю, що так, якщо домен відображення встановлений 1, ..., nу такому порядку. Чи можете ви уточнити, як відображення може бути вхідним? Це структура даних?
Луїс Мендо

@LuisMendo Так, це структура даних, як Python dict. Я хочу мати {1: 2, 2: 1}замість цього вхід [2, 1].
Мідь

Відповіді:


12

J, 4 байти

#@C.

Це передбачає, що перестановка заснована на 0. Він використовує вбудований, C.який надає список, що представляє пряму перестановку, виводить список циклів. Потім #складене @на цьому повертає кількість циклів у цьому списку.

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


1
Це обман! :)
orlp

1
Я повинен був заборонити вбудовані :-D
Луїс Мендо

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

@miles Nah, я залишу його як є. Хороша робота!
Луїс Мендо

7

JavaScript, 99 98 байт

Це рішення передбачає масив і його значення нульово індексуються (наприклад [2, 1, 0]).

f=a=>{h={},i=c=0;while(i<a.length){s=i;while(!h[i]){h[i]=1;i=a[i]}c++;i=s;while(h[++i]);}return c}

Пояснення

// assumes the array is valid and zero-indexed
var findCycles = (array) => {
    var hash = {};  // remembers visited nodes
    var index = 0;  // current node
    var count = 0;  // number of cycles
    var start;      // starting node of cycle

    // loop until all nodes visited
    while(index < array.length) {
        start = index;  // cache starting node

        // loop until found previously visited node
        while(!hash[index]) {
            hash[index] = 1;    // mark node as visited
            index = array[index];   // get next node
        }
        count++;    // increment number of cycles

        index = start + 1;  // assume next node is right after

        // loop until found unvisited node
        while(hash[index]) {
            index++;    // get next node
        }
    }

    return count;   // return number of cycles
};

3
Ласкаво просимо до PPCG! Приємна перша відповідь! Це також одна з найкращих, якщо не найкраща перша відповідь, яку я бачив у своєму досвіді! Продовжуй гарно працювати!
GamrCorps

Дякую тобі велике спасибі! Мені довелося шукати, як робити лямбдаси в JavaScript. Я ще не такий знайомий з речами ES6.
kamoroso94

6

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

Length@ConnectedComponents@Thread[Sort@#->#]&

Він генерує графік і рахує його з'єднані компоненти.


6

Математика, 37 28 27 байт

#~PermutationCycles~Length&

Дякуємо @alephalpha за збереження 9 байт, а @miles - ще 1 байт.


3
PermutationCycles[#,Length]&
алефальфа

3
О, це акуратно. Я не знав, що PermutationCyclesможна взяти другий аргумент, щоб змінити голову його результату. Ви також можете використовувати позначення інфіксації, щоб зберегти ще один байт #~PermutationCycles~Length&.
милі

1
Що стосується вашого оригінального рішення, #&це трохи коротше, ніж Identity. ;)
Мартін Ендер

6

Пітон, 77 69 67 байт

f=lambda p,i=1:i and0 **p[i-1]+f(p[:i-1]+[0]+p[i:],p[i-1]or max(p))

(not p[i-1])можна зробити як0**p[i-1]
xnor

5

Желе, 12 10 9 байт

ị³$ÐĿ«/QL

Збережено 1 байт завдяки @ Dennis .

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

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

Пояснення

ị³$ÐĿ«/QL  Input: permutation p
  $        Chain (ị³) as a monad
 ³           The input p
ị            For each value x, get the value at index x in p
   ÐĿ      Invoke it on p initially, and repeat it on its next value until it returns
           to a previous value and keep track of the results
           This will create a table where each column is the orbit of each value
     «/    Get the minimum value along each column of that table
       Q   Deduplicate
        L  Get the length and return

Дуже приємний підхід!
Луїс Мендо

ị³$ÐĿ«/QLповинен працювати.
Денніс

@Dennis Wow, це акуратний трюк! Оскільки кожен цикл роз'єднаний, то, якщо взяти або максимум / хв, і використовувати його як мітку, буде достатньо для виведення дублікату + довжина для результату.
миль

5

Пітон, 64 байти

l=input()
for _ in l:l=[min(x,l[x])for x in l]
print len(set(l))

Цей код для гольфу є ідіоматичним і читабельним. Використовує 0-індексацію.

Кожне значення розглядає, на що воно вказує, і на що вказує вказане значення, і вказує на меншу з двох. Після достатньої кількості повторень кожен елемент вказує на найменший елемент свого циклу. Кількість відокремлених елементів - це кількість циклів.

Досить робити nітерації. Або ми можемо повторювати, поки список більше не змінюється. Ця стратегія дала мені рекурсивну функцію однакової довжини, 64 байти:

f=lambda l,p=0:len(set(l*(l==p)))or f([min(x,l[x])for x in l],l)

Скорочення склало 65 байт

lambda l:len(set(reduce(lambda l,_:[min(x,l[x])for x in l],l,l)))

Ці set(_)перетворення можуть бути скорочені , щоб {*_}в Python 3.5, заощадивши 2 байта.


4

Haskell, 111 байт

l!i|l!!i<0=l|1<2=(take i l++[-1]++drop(i+1)l)!(l!!i)
f(x:y)|x>=0=0|1<2=1+f y
c l|l==[-1|x<-l]=0|1<2=1+c(l!f l)

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


4
Чорт, вам краще мати гарний шрифт програмування :)1l!i|iIi!!1ll1|
orlp

@orlp і це 111 байт! : O
grooveplex


3

JavaScript (ES6), 49 байт

a=>a.reduce(g=(c,e,i)=>e<i?g(c,a[e],i):c+=e==i,0)

Використовується індексація на основі нуля. Пояснення: reduceвикористовується для виклику внутрішньої функції gкожного елемента масиву. c- кількість циклів, e- елемент масиву, i- індекс масиву. Якщо елемент менший за індекс, то це потенційний цикл - елемент використовується для індексації в масив, щоб знайти наступний елемент циклу рекурсивно. Якщо ми починаємо або закінчуємо початковим індексом, то це новий цикл, і ми збільшуємо кількість циклів. Якщо в будь-якій точці ми знайдемо значення, що перевищує індекс, тоді цей цикл будемо рахувати пізніше.


Коли я запустив ваш код у масиві [2,1,0,3,4,5], він зазнав аварії з цим повідомленням "Максимальний розмір стека викликів перевищено".
kamoroso94

1
@ kamoroso94 Вибачте з цього приводу, що друкарня підкралася. Слід виправити зараз.
Ніл

2

C, 90 байт

Виклик f()із змінним intмасивом, індексація на основі 1. Другий параметр - розмір масиву. Функція повертає кількість циклів.

i,j,c;f(a,n)int*a;{for(c=i=0;i<n;++i)for(j=0,c+=!!a[i];a[i];a[i]=0,i=j-1)j=a[i];return c;}

Спробуйте це на ideone .

Алгоритм:

For each index
    If index is non-zero
        Increment counter
        Traverse the cycle, replacing each index in it with 0.

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