Puan Tarzan'ın Olimpiyat Asma Bağlanma Rutini


32

Olimpiyat sarmalayıcıları rutinlerini standart ağaçlarda yaparlar. Özellikle, standart ağacı niçin köşe sahip 0aracılığıyla yukarı n-1ve her sıfır olmayan bir tepe bağlantı kenarları avertexe n % aaltında. Örneğin, Standart Ağaç 5 şuna benzer:

3
|
2   4
 \ /
  1
  |
  0

5 bölü 5 olduğunda kalan 2 2, 5 bölü 2 veya 4 kalan kalan 1, 5 bölü 5 ise 1 olur.

Bu yıl Tarzan, altını her biri tepe noktasında başlayan, tepe noktasına n - 1sallanan, tepe n - 2noktasına n - 3vb 0. Geçecek kadar yeni rutinler ile savunacak .

Bir rutinin puanı, her vuruş için puanların toplamıdır (çıkarma işlemi dahil) ve vuruş için puan ağacı içindeki başlangıç ​​ve bitiş noktaları arasındaki mesafedir. Böylece, Tarzan'ın Standart Ağaç 5'teki rutini 6:

  • Bir salınım 4için 3skorlar üç nokta (yukarı, aşağı, yukarı),
  • bir puan (aşağı) puan 3için bir salıncak 2,
  • bir puan (aşağı) puan 2için bir salıncak 1, ve
  • bir puan (aşağı) 1için bir sökme 0.

Olumlu bir tamsayı verilen nTarzan'ın rutininin Standart Ağaç'taki puanını hesaplayan bir program veya işlev yazın n. Örnek girişler ve çıkışlar:

 1 ->  0
 2 ->  1
 3 ->  2
 4 ->  6
 5 ->  6
 6 -> 12
 7 -> 12
 8 -> 18
 9 -> 22
10 -> 32
11 -> 24
12 -> 34
13 -> 34
14 -> 36
15 -> 44
16 -> 58
17 -> 50
18 -> 64
19 -> 60
20 -> 66
21 -> 78
22 -> 88
23 -> 68
24 -> 82

Kurallar ve kod puanlama, için her zamanki gibi .


9
OEIS’de bu sırayı bulamıyorum. Güzel soru.
Sızdıran Rahibe,

8
Mükemmel özellik!
xnor

1
@LeakyNun Yine de eklenmelidir. Bu çok orijinal bir sekans! (Backstory olmadan bile)
DanTheMan

Yanıtlar:


12

C, 98 97 bayt

F(i){int c[i],t=i-2,n=0,p;for(;++n<i;)for(p=c[n]=n;p=i%p;c[p]=n)t+=c[p]<n-1;return i>2?t*2:i-1;}

Bu, aşağıdaki formülle her bir nokta çifti arasındaki mesafeyi hesaplar:

  • Kökten A düğümüne olan mesafeyi ekleyin
  • Kökten B düğümüne olan mesafeyi ekleyin
  • Çıkartma 2 * A ve B ortak kökünün uzunluğu

Bu, tüm çiftlere uygulandığında, aynı olması avantajına sahiptir:

  • Kökten her düğüme 2 * mesafe ekle
  • Çıkartma 2 * her bir düğüm çiftinin ortak kökünün uzunluğu
  • Kökten ilk düğüme olan mesafeyi çıkarın
  • Kökten son düğüme olan mesafeyi çıkarın

Mantığı daha basit hale getirmek için, soru belirtildiği gibi n-1'den 0'a değil, nod 1'den n-1 noduna geçeceğimizi varsayıyoruz. Kök düğümden düğüm 0'a olan uzaklık açıkça 0'dır (aynıdır). Ve (çoğu) ağaçlar için, son düğümden köke olan mesafenin 2 olduğunu görebiliriz:

                    n+1 % n = 1  for all n > 1
and:                  n % 1 = 0  for all n >= 0
therefore:  n % (n % (n-1)) = 0  for all n > 2

Bu, bazı özel vakalarımız olduğu anlamına gelir (n <2), ancak yeterince kolay olanları hesaba katabiliriz.

Yıkmak:

F(i){                               // Types default to int
    int c[i],                       // Buffer for storing paths
        t=i-2,                      // Running total score
        n=0,                        // Loop index
        p;                          // Inner loop variable
    for(;++n<i;)                    // Loop through all node pairs (n-1, n)
        for(p=c[n]=n;p=i%p;c[p]=n)  //  Recurse from current node (n) to root
            t+=c[p]<n-1;            //   Increase total unless this is a common
                                    //   node with the previous path
    return i>2?   :i-1;             // Account for special cases at 1 and 2
               t*2                  // For non-special cases, multiply total by 2
}

1 bayt için teşekkürler @feersum kaydedildi


Bonus: Ağaçlar!

Bu ağaçların neye benzediğini görmek için hızlı ve kirli bir program yazdım. İşte sonuçlardan bazıları:

6:

5 4  
| |  
1 2 3
 \|/ 
  0  

8:

  5      
  |      
7 3   6  
|  \ /   
1   2   4
'--\|/--'
    0    

13:

   08              
    |              
11 05   10 09 07   
 |   \ /    |  |   
02   03    04 06 12
 '-----\  /---'--' 
        01         
         |         
        00         

19:

   12                       
    |                       
   07   14                  
     \ /                    
     05    15 11            
       \  /    |            
17      04    08 16 13 10   
 |       '-\  /--'   |  |   
02          03      06 09 18
 '---------\ |/-----'--'--' 
            01              
             |              
            00              

49:

                         31                                                    
                          |                                                    
           30            18   36                                               
            |              \ /                                                 
           19   38 27      13    39 29    32                                   
             \ /    |        \  /    |     |                                   
   26        11    22 44      10    20 40 17   34                              
    |         '-\  /--'        '-\  /--'    \ /                                
47 23   46       05               09        15    45 43 41 37 33 25    35 28   
 |   \ /          '--------------\ |/-------'-----'   |  |  |  |  |     |  |   
02   03                           04                 06 08 12 16 24 48 14 21 42
 '----'--------------------------\ |/----------------'--'--'--'--'--'    \ |/  
                                  01                                      07   
                                   '-----------------\  /-----------------'    
                                                      00                       

Return ifadesinde bazı gereksiz parantezler var.
feersum,

@feersum d'oh! Her zaman gereksiz olmadılar, ama sonra özel durum işlemeyi değiştirdim. Teşekkürler!
Dave

3
Görselleştirmeleri seviyorum!
Edward

7

Python 2,85 bayt

def f(a,i=1):h=lambda n:n and{n}|h(a%n)or{0};return i<a and len(h(i)^h(i-1))+f(a,i+1)

7

Perl, 65 59 55 54 bayt

İçin +2 içerir -ap

STDIN'de ağaç boyuyla koş:

for i in `seq 24`; do echo -n "$i: "; vines.pl <<< $i; echo; done

vines.pl:

#!/usr/bin/perl -ap
$_=map{${"-@F"%$_}|=$_=$$_|$"x$p++.1;/.\b/g}1-$_..-1

açıklama

Ağacı yeniden yazarsan

3
|
2   4
 \ /
  1
  |
  0

her düğümün atalarının ve kendi kümelerinin bulunduğu bir yere:

 {3}
  |
{2,3}   {4}
   \    /
    \  /
  {1,2,3,4}
      |
 {0,1,2,3,4}

O zaman örneğin tüm düğümleri 4 - 3 arasındaki yolu şöyle tanımlayabiliriz:

  • 3 içeren ancak 4 olmayan tüm düğümler (3'ten aşağıya iniyor)
  • 4 içeren ancak 3 olmayan tüm düğümler (4'ten aşağıya iniyor)
  • Hem 3 hem de 4'ü içeren en yüksek düğüm (birleştirme)

Kenarların sayısı düğüm sayısından daha azdır, bu nedenle birleşme noktasını yoksaymak için kullanabiliriz, bu nedenle yoldaki kenar sayısı 4'ten 3'e kadardır, çünkü:

  • 3 içeren ancak 4: 2 düğüm içermeyen düğümlerin sayısı
  • 4 içeren ancak 3: 1 düğüm içermeyen düğümlerin sayısı

Bunun doğrudan hedefine inen bir yol için de işe yaradığına dikkat edin, örneğin 3 ila 2 arasındaki yol için kenar sayısı 1'dir:

  • 2 içeren ancak 3: 0 düğüm içermeyen düğüm sayısı
  • 3: 2: 1 düğümü içermeyen düğümlerin sayısı

Daha sonra tüm bu kombinasyonları toplayabiliriz.

Bunun yerine sadece bir düğüme bakarsanız, örneğin ata setli 2. düğüm {2,3}. Bu düğüm yolu 2 to 12'ye 1 ama içerdiği için yol açtığında bir kez katkıda bulunacak. 3 to 2Hem 2 hem de 3'e sahip olduğu için yol için hiçbir şeye katkıda bulunmayacak , ancak 3'ten 4 to 3beri yolu işlerken bir kez katkıda bulunacak , ancak hayır 4. Genel olarak, bir düğüm kümesinin ata kümesindeki bir sayı, kümede olmayan her komşu için bir tane (daha aşağıdan yukarıya) katkıda bulunacaktır. Yolun olmadığından, sadece düşük komşu 3'e katkıda bulunan azami unsur (bu durumda 4) hariç5 to 4. Simüler 0 tek taraflıdır, ancak 0 her zaman ağacın kökündeyken ve tüm sayıları içerdiğinden (nihai birleşme ve birleştirme sayılmaz) 0'dan hiçbir zaman katkısı olmaz. tamamen dışarı.

Böylece sorunu, her düğüm için belirlenen ataya bakarak çözebiliriz, katkıları sayabilir ve tüm düğümler üzerinde toplayabiliriz.

Komşuları kolayca işlemek için ata kümelerini bir boşluk dizesi olarak temsil edeceğim ve p pozisyonundaki her bir 1'in n-1-p'nin bir ata olduğunu temsil ettiği yerlerden biri. Dolayısıyla, örneğin bizim durumumuzda n=50, 0 konumunda, 4'ün bir ata olduğunu belirtir. Sondaki boşlukları bırakacağım. Yani inşa edeceğim ağacın gerçek temsili şudur:

" 1"
  |
" 11"   "1"
   \    /
    \  /
   "1111"

Düğüm 0'ı "11111"yoksaymayacağım için (hiçbir zaman katkıda bulunmaz) gösterdiğim için düğüm 0'ı dışarıda bıraktığımı fark et .

Alt komşusu olmayan atalar şimdi 1'lerin sırasının sonu ile temsil edilir. Daha yüksek komşusu olmayan atalar, şimdi 1'lerin bir dizisinin başlangıcıyla temsil edilir, ancak bir dizgenin başlangıcındaki herhangi bir dizinin başlangıcını yoksaymalıyız, çünkü bu 5 to 4varolmayan yolu temsil edecektir . Bu kombinasyon tam olarak regex ile eşleştirilir /.\b/.

Ata dizgilerinin oluşturulması, tüm düğümlerin sırayla işlenmesiyle yapılır n-1 .. 1ve burada düğümün kendisinde bir 1 belirlenir ve soyundan bir "veya" yapılır.

Tüm bunlarla programın anlaşılması kolaydır:

-ap                                                  read STDIN into $_ and @F

   map{                                    }1-$_..-1 Process from n-1 to 1,
                                                     but use the negative
                                                     values so we can use a
                                                     perl sequence.
                                                     I will keep the current
                                                     ancestor for node $i in
                                                     global ${-$i} (another
                                                     reason to use negative
                                                     values since $1, $2 etc.
                                                     are read-only
                       $$_|$"x$p++.1                 "Or" the current node
                                                     position into its ancestor
                                                     accumulator
                    $_=                              Assign the ancestor string
                                                     to $_. This will overwrite
                                                     the current counter value
                                                     but that has no influence
                                                     on the following counter
                                                     values
       ${"-@F"%$_}|=                                 Merge the current node
                                                     ancestor string into the
                                                     successor
                                                     Notice that because this
                                                     is an |= the index
                                                     calculation was done
                                                     before the assignment
                                                     to $_ so $_ is still -i.
                                                     -n % -i = - (n % i), so
                                                     this is indeed the proper
                                                     index
                                     /.\b/g          As explained above this
                                                     gives the list of missing
                                                     higher and lower neighbours
                                                     but skips the start
$_=                                                  A map in scalar context
                                                     counts the number of
                                                     elements, so this assigns
                                                     the grand total to $_.
                                                     The -p implicitly prints

Bunun yerine /.\b/, /\b/tarzan'ın da yol açtığı bu sorunun gidiş dönüş sürümünü çözdüğüne dikkat edin0 to n-1

Ata dizelerinin nasıl göründüğüne dair bazı örnekler (sıra ile verilmiştir n-1 .. 1):

n=23:
1
 1
  1
   1
    1
     1
      1
       1
        1
         1
          1
          11
         1  1
        1    1
       1      1
      11      11
     1          1
    11  1    1  11
   1              1
  1111  11  11  1111
 111111111  111111111
1111111111111111111111
edges=68

n=24:
1
 1
  1
   1
    1
     1
      1
       1
        1
         1
          1
           1
          1 1
         1   1
        1     1
       1       1
      1         1
     1  1     1  1
    1             1
   11    1   1    11
  1   1         1   1
 1        1 1        1
1                     1
edges=82

Hata! Üzgünüz, düzenlemenizin yalnızca birkaç saniye eski olduğunu bilmiyordum. Neyse, çok temiz bir yaklaşım ve açıklama!
FryAmTheEggman

@FryAmTheEggman Sorun değil, sadece aynı düzen sorununu çözüyorduk. Her neyse, evet, tüm programların bu programda nasıl bir araya gelmesinden çok memnunum. Şu anda kesilecek yağ göremiyorum ..
Ton Hospel

3

Mathematica, 113 103 102 bayt

(r=Range[a=#-1];Length@Flatten[FindShortestPath[Graph[Thread[r<->Mod[a+1,r]]],#,#2]&@@{#,#-1}&/@r]-a)&

@Feersum sayesinde -10 bayt; @MartinEnder sayesinde -1 bayt

Aşağıdakiler çok daha hızlı (ancak daha uzun, ne yazık ki, 158 baytta ):

(a=#;If[a<4,Part[-{1,1,1,-6},a],If[EvenQ@a,-2,1]]+a+4Total[Length@Complement[#,#2]&@@#&/@Partition[NestWhileList[Mod[a,#]&,#,#!=0&]&/@Range@Floor[a/2],2,1]])&

Kullanmadan bir şeyler atayabileceğine inanıyorum With. Ayrıca her seferinde Rangekullanılmış gibi görünüyor a, argümandır, bu da hesaba katılabilir.
feersum

1
r=Range[a=#-1]bir bayt kaydeder.
Martin Ender

2

J, 37 bayt

[:+/2(-.+&#-.~)/\|:@(]|~^:(<@>:@[)i.)

Kullanımı:

   f=.[:+/2(-.+&#-.~)/\|:@(]|~^:(<@>:@[)i.)
   f 10
32
   f every 1+i.20
0 1 2 6 6 12 12 18 22 32 24 34 34 36 44 58 50 64 60 66

Burada çevrimiçi deneyin.


Bunun nasıl çalıştığını gösteren bir döküm görmek istiyorum. Ayrıca tryj.tk servisi bozulmuş gibi görünüyor ("localStorage okuyamadı…" ve "$ (…) .terminal bir işlev değil")
Dave

@Dave bu site benim için de Chrome'da çalışmıyor, ancak IE veya Edge kullanıyorsanız çalışır, ancak ilgileniyorsanız J ( link ) yüklemenizi öneririm !
mil,

@miles Weird, benim için tüm tarayıcılar için çalışıyor (FF, Chrome, IE).
randomra

Chrome'u kullanarak benim için işe yaradı, ancak birkaç ay önce çalışmayı durdurdu ve Dave's
miles

@Edward Biraz zaman bulduğum zaman yapacağım.
randomra

1

JavaScript (ES6), 118 116 bayt

n=>[...Array(n)].map(g=(_,i)=>i?[...g(_,n%i),i]:[],r=0).reduce(g=(x,y,i)=>x.map(e=>r+=!y.includes(e))&&i?g(y,x):x)|r

Ayarlanmış bir fark fonksiyonunun eksikliği gerçekten acı verir, ancak bazı yaratıcı özyineleme, bayt sayısını biraz azaltır. Düzenleme: Gereksiz bir parametre kaldırarak 2 bayt kaydedildi.

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.