Bir permütasyonun devir sayısı


23

Bunun için tamsayıların , ... gibi bir permütasyon düşünün :1nn = 6

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

Eğer bir eşleme olarak permütasyon görüntülerseniz [1,2,3,4,5,6]için [5,2,4,3,6,1], permütasyon ayrık içine decomponsed edilebilir döngüleri . Döngü, birbirine eşlenen öğelerin alt kümesidir. Örneğin, 1eşlenecek 5, eşlenecek 6, geri eşlenecek 1. Yani bir döngü [1,5,6]. Diğer çevrimler [2]ve [3,4]. Böylece bu permütasyon için döngü sayısı3 .

Genel olarak, bir permütasyonun döngüleri benzersizdir (siparişe göre) ve büyüklükte bir permütasyon için döngü sayısı ila narasında değişir .1n

Meydan okuma

Boş olmayan bir permütasyon verildiğinde, döngü sayısını verin.

Girdi oluşturduğu bir dizidir ntamsayılar 1, 2, ..., n, nerede n > 0. Her tamsayı tam olarak bir kez oluşur. Göründükleri sıra yukarıdaki örnekte olduğu gibi permütasyonu tanımlar.

Bir dizi yerine bir liste, sayılar arasında bir ayırıcıya sahip bir dize, her sayı için ayrı bir giriş veya makul olan herhangi bir şey kullanabilirsiniz.

Boyut ntabanlı bir tamsayı için 1, 1 tabanlı tamsayılar kümesi yerine n, 0 tabanlı 0, ..., n-1. Eğer öyleyse, lütfen cevabınızı belirtiniz.

Kod için çalışması gerektiğini netmek kadar 20makul bir süre içinde, az bir dakika daha demek.

Kod golfü. Tüm yapılara izin verilir.

Test durumları

Bu 1 tabanlı dizi girişini varsayar.

 [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

İlgili

Bu ilgili zorluk , sayısını değil, permütasyonun gerçek çevrimlerini sorar. Yalnızca döngü sayısını gerektirmek, gerçek döngüleri oluşturabilen daha kısa algoritmalara yol açabilir.


Benim sorum boşuna, 0-temelli girdilere izin veriliyor.
orlp

@orlp Bu hızlı oldu! Sorunuzu bile görmedim
Luis Mendo

Girdi olarak değerlerin indeks eşlemesini alabilir miyiz?
Bakır

1
@Copper Evet, eşlemenin etki alanı küme 1ise ..., bu nsırada olduğunu düşünüyorum. Bir eşlemenin nasıl bir girdi olabileceğini açıklayabilir misiniz? Veri yapısı mı?
Luis Mendo

@LuisMendo Evet, Python gibi bir veri yapısı dict. Bunun {1: 2, 2: 1}yerine bir girdi olarak sahip olmak istiyorum [2, 1].
Bakır,

Yanıtlar:


12

J, 4 bayt

#@C.

Bu, permütasyonun 0-temelli olduğunu varsayar. C.Direkt permütasyonu temsil eden bir liste verilen yerleşik çevrimleri kullanır. Daha sonra #oluşan @bu listedeki döngü sayısını geri gelir.

Burada dene.


1
Bu hile yapmaktır! :)
orlp

1
Yerleşikleri yasaklamalıydım:
Luis Mendo

2
Yerleşikler sevgidir. Yerleşikler hayattır. Yerleşiklerin yasaklanmasıyla daha eğlenceli olacağını kabul ediyorum. Çok fazla cevap almadan hemen önce kuralı değiştirmek için çekinmeyin.
mil:

@miles Nah, olduğu gibi bırakacağım. Aferin!
Luis Mendo

7

JavaScript, 99 98 bayt

Bu çözüm dizinin var olduğunu ve değerlerinin sıfır indeksli olduğunu varsaymaktadır (örneğin [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}

açıklama

// 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'ye Hoşgeldiniz! Güzel ilk cevap! Bu aynı zamanda en iyilerden biri, en iyisi değilse de, deneyimimde gördüğüm ilk cevap! İyi çalışmaya devam et!
GamrCorps

Vay, çok teşekkür ederim! Aslında JavaScript'te lambdaların nasıl yapıldığını araştırmam gerekti. Henüz ES6 olaylarına aşina değilim.
kamoroso94

6

Mathematica, 45 bayt

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

Bir grafik oluşturur ve bağlı bileşenlerini sayar.


6

Mathematica, 37 28 27 bayt

#~PermutationCycles~Length&

9 byte tasarruf için @ alephalpha ve 1 byte daha miller için teşekkürler.


3
PermutationCycles[#,Length]&
alephalpha

3
Oh, bu temiz. PermutationCyclesÇıktısının başını değiştirmek için ikinci bir argüman alabileceğini bilmiyordum . Bir başka byte'ı kaydetmek için infix notasyonunu da kullanabilirsiniz #~PermutationCycles~Length&.
mil

1
Ayrıca orijinal çözümünüzle ilgili olarak, #&biraz daha kısa Identity. ;)
Martin Ender

6

Python, 77 69 67 bayt

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])olarak yapılabilir0**p[i-1]
xnor

5

Jöle, 12 10 9 bayt

ị³$ÐĿ«/QL

@ 1 bayt kaydedildi Dennis .

Bu 1 tabanlı permütasyonları kullanır. Önceki değerleri korurken, önceki bir permütasyona ulaşana kadar permütasyonu tekrar tekrar uygulayarak çalışır. Değişiklikleri takip ederek, o tablonun sütunları boyunca her değer için yörünge yaratacaktır. Ardından, her sütunun minimum veya maksimumunu bularak, bu döngü için bir etiket oluşturulabilir. Sonra, bu etiketlerin listesini tekilleştirin ve ayrık döngülerin sayısı olacak olan uzunluğu elde edin.

Burada dene.

açıklama

ị³$ÐĿ«/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

Çok güzel bir yaklaşım!
Luis Mendo

ị³$ÐĿ«/QLçalışmalı.
Dennis

@Dennis Vay, bu temiz bir numara! Her döngü ayrık olduğundan, en fazla / dak değerinin alınması ve bunu bir etiket olarak kullanmak, sonuç için + uzunluk değerini tekilleştirmek için yeterli olacaktır.
mil

5

Python, 64 bayt

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

Bu golf kodu, deyimsel ve okunabilir olur. 0 indeksleme kullanır.

Her değer neye işaret ettiğini ve sivri değerin neye işaret ettiğini ve ikisinin daha küçük olduğunu gösterir. Yeterli tekrarlardan sonra, her bir eleman kendi döngüsünün en küçük elemanına işaret eder. İşaret edilen farklı elemanların sayısı daha sonra döngülerin sayısıdır.

nYineleme yapmak için yeterli . Alternatif olarak, liste artık değişmeyene kadar yineleyebiliriz. Bu strateji bana aynı uzunlukta, 64 byte özyinelemeli bir işlev verdi:

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

Azaltma 65 bayttır

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

set(_)Dönüşümlerine kısaltılabilir {*_}2 bayt tasarruf Python 3.5.


4

Haskell, 111 bayt

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-tabanlı indeksleme kullanır


4
Kahretsin, iyi bir programlama fontu olsa iyi olur :)1l!i|iIi!!1ll1|
orlp

@orlp ve 111 bayt! : O
grooveplex

4

Pyth, 9 bayt

l{mS.u@QN

0 tabanlı dizinleri kullanır. Çevrimiçi deneyin .

Nasıl çalışır

  m         map for d in input:
    .u        cumulative fixed-point: starting at N=d, repeatedly replace N with
      @QN       input[N]
              until a duplicate is found, and return all intermediate results
   S          sort
 {          deduplicate
l           length

3

JavaScript (ES6), 49 bayt

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

Sıfır tabanlı endeksleme kullanır. Açıklama: dizinin her elemanındaki reduceiç işlevi çağırmak için kullanılır g. cdöngü sayısı e, dizi elemanı, idizi indeksidir. Eğer eleman endeksten az ise, o zaman potansiyel bir döngüdür - eleman döngüdeki bir sonraki öğeyi tekrarlı olarak bulmak için diziye endekslemek için kullanılır. Eğer orjinal indeks ile başlamış veya bitmiş olursak, bu yeni bir döngüdür ve döngü sayısını arttırırız. Herhangi bir noktada dizinden daha büyük bir değer bulursak, o zaman bu çevrimi sayarız.


Kodunuzu dizide koştuğumda, [2,1,0,3,4,5]"Maksimum çağrı yığını boyutu aşıldı" mesajı ile düştü.
kamoroso94

1
@ kamoroso94 Bunun için üzgünüm, bir yazım hatası geldi. Şimdi düzeltilmeli.
Neil

2

C, 90 bayt

f()Değişken bir intdizi, 1 tabanlı indeksleme ile çağırın . İkinci parametre dizinin büyüklüğüdür. Fonksiyon döngü sayısını döndürür.

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;}

İdeone üzerinde deneyin .

Algoritması:

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

2

GAP , 30 bayt

Basit, ikinci argüman Cycles , permütasyonun üzerinde çalışması gereken seti verir:

l->Size(Cycles(PermList(l),l))
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.