Collatz Kuzenlerini Hesaplamak


21

Fonksiyon tanımlama f (n), bir pozitif tamsayı , n , aşağıdaki gibi:

  • n / 2 , n eşitse
  • 3 * n + 1 , n tuhafsa

Tekrar tekrar herhangi Bu işlevi uygularsanız n 0'dan büyük (kimsenin henüz kanıtlamak mümkün olmuştur gerçi), sonuç her zaman 1'e yakınsama görünüyor. Bu özellik Collatz Conjecture olarak bilinir .

Bir tamsayı en tanımlayın durdurma zamanı size Collatz fonksiyonu aracılığıyla geçmek zorunda kaç kez olarak f o 1. İşte ilk 15 tamsayılar durdurma zamanlardır ulaşmadan önce:

1  0
2  1
3  7
4  2
5  5
6  8
7  16
8  3
9  19
10 6
11 14
12 9
13 9
14 17
15 17

Diyelim ki aynı durma süresi Collatz kuzenleri ile herhangi bir sayı kümesini çağıralım . Örneğin, 5 ve 32, 5 duraklama süresi olan Collatz kuzenleridir.

Göreviniz: negatif olmayan bir tamsayı alan ve durma süresi bu tamsayıya eşit olan Collatz kuzenleri setini üreten bir program veya işlev yazın.

Giriş

STDIN, ARGV veya fonksiyon argümanı ile verilen negatif olmayan bir tamsayı S.

Çıktı

Durdurma zamanı S tüm numaralar listesi, sıralanmış içinde yükselen düzeni. Liste programınız tarafından çıkarılabilir veya işleviniz tarafından döndürülebilir veya çıkarılabilir. Çıktı formatı esnektir: sayılar birbirinden kolayca ayırt edilebildiği sürece boşlukla ayrılmış, yeni satırla ayrılmış veya dilinizin herhangi bir standart liste biçimi iyidir.

Gereksinimler

Gönderiniz herhangi bir S ≤ 30 için doğru sonuçlar vermelidir. Saat veya gün değil, saniye veya dakika olarak bitmelidir.

Örnekler

0  -> 1
1  -> 2
5  -> 5, 32
9  -> 12, 13, 80, 84, 85, 512
15 -> 22, 23, 136, 138, 140, 141, 150, 151, 768, 832, 848, 852, 853, 904, 906, 908, 909, 5120, 5376, 5440, 5456, 5460, 5461, 32768

İşte S = 30 için çıktının bir özeti .

Bu : bayt cinsinden en kısa program kazanır. İyi şanslar!


Döngülerden ne haber? Döngüden kaçınma sözünü görmedim. Çünkü S = 5 için 3 değer var [4, 5, 32] çünkü "1 - 2 - 4 - 1 - 2- 4"
JPMC

1
@ JPMC Döngüsü önleme, durma zamanının tanımı ile ifade edilir. 4'ün durma süresi 2 değil 5'tir, çünkü 2 "1'e ulaşmadan önce Collatz işlevinden geçirmeniz gereken sayıdır."
DLosc

Ah, affet beni. Bir sayının birden fazla durma süresine sahip olabileceğini düşünüyordum, çünkü birden fazla yol buna yol açabilir. Fakat bu, 1'den fazla, N'den çalışmayanlar için yapıldı. Üzgünüm.
JPMC

1
Elbette @Dosc Pyth.
isaacg

Yanıtlar:


7

Pyth, 26 24 21 bayt

Su+yMG-/R3fq4%T6G1Q]1

Bu kod anında çalışır S=30. Kendiniz deneyin: Gösteri

5 bayt tasarrufu için @isaacg teşekkür ederiz.

açıklama

1Kodum Collatz işleviyle başlıyor ve bunları geri alıyor. Tüm sayılar eşler darasında S-1adım 2*dve (d-1)/3. Sonuncusu da her zaman geçerli değil.

                        implicit: Q = input number
                   ]1   start with G = [1]
 u                Q     apply the following function Q-times to G:
                          update G by
   yMG                      each number in G doubled
  +                       +
          fq4%T6G           filter G for numbers T, which satisfy 4==T%6
       /R3                  and divide them by 3
      -          1          and remove 1, if it is in the list
                            (to avoid jumping from 4 to 1)
S                       sort the result and print

Bu güzel bir kullanım -F.
isaacg

1
- ... 1Düşürme içindeki toplamı etrafına koyarsanız , azalmanın a .u, ne de -Fdışarıda olması gerekmez . 2 karakter kaydeder.
isaacg,

@isaacg Teşekkürler. Aslında önceki bir sürümde bu vardı, ancak hata ayıklama sırasında kaldırıldı.
Jakube,

3
Kendi cevabım için @ Isaac'den ödünç aldım. Saatleri, kopyaları kaldırmak için en kısa kodu bulmaya çalışarak geçirdim, ancak bu çok şık bir çözüm. Ayrıca, geçersiz bölümleri atmak için bir demet kullanmanızdan gerçekten hoşlanıyorum. Ne yazık ki, CJam'da tote yok, ancak geçersiz bölümleri 1 olarak eşleştirmeyi başardım.
Dennis

@Jakube q4%d6eşittir !%hhd6, ancak 1 karakter daha kısadır.
isaacg

8

Mathematica, 98 92 89 bayt

Bu çözüm S = 30hemen çözer :

(p={0};l={1};Do[l=Complement[##&@@{2#,Mod[a=#-1,2]#~Mod~3~Mod~2a/3}&/@l,p=p⋃l],{#}];l)&

Bu, Stek parametresi olarak alan ve Collatz kuzenlerinin bir listesini döndüren adsız bir fonksiyondur .

Algoritma basit bir genişlik ilk aramasıdır. Verilen bir için Collatz kuzenleri Siçin Collatz kuzenleri ulaşılabilir bütün tam sayılar S-1aracılığıyla 2*nveya ulaşılabilir tek sayı (n-1)/3. Ayrıca yalnızca ilkS aşamadan sonra ulaşılan tam sayıları ürettiğimizden emin olmalıyız , bu nedenle önceki tüm kuzenleri takip pedip sonuçtan çıkardık . Yine de yaptığımız için, önceki tüm kuzenlerden (sadece bunlardan değil) gelen adımları hesaplayarak birkaç byte tasarruf edebiliriz S-1(bu, onu biraz daha yavaşlatır, ancak ihtiyaç duyulan şekilde fark etmez S).

İşte biraz daha okunabilir bir versiyon:

(
  p = {0};
  l = {1};
  Do[
    l = Complement[
      ## & @@ {2 #, Mod[a = # - 1, 2] #~Mod~3~Mod~2 a/3} & /@ l,
      p = p ⋃ l
    ]~Cases~_Integer,
    {#}
  ];
  l
) &

5

Python 2, 86 83 75 73 71 bayt

f=lambda n,k=1:sorted([k][n:]or(k>4==k%6and f(n-1,k/3)or[])+f(n-1,k*2))

Gibi ara f(30). n = 30hemen hemen anlık.

( kBir kuzen listesi yerine bir sayı olarak tekrarlama fikri için @DLosc'a ve birkaç bayta teşekkürler. Bırakma için @ isaacg'a teşekkür ederiz ~-.)

Bu değişken daha kısa, ancak maalesef üstel dallanma nedeniyle çok uzun sürüyor:

f=lambda n,k=1:sorted([k][n:]or(k>4==k%6)*f(n-1,k/3)+f(n-1,k*2))

İlginç - benim orijinal çözüm çok benzer, ancak (sizinkinden birkaç optimizasyonlar alarak) 2 kısa bayt çıkıyor: f=lambda d,n=1:d and sorted(sum((c(d-1,x)for x in[n*2]+[~-n/3][:n>4==n%6]),[]))or[n]. İşlev çağrıları ile daha az etkilidir ancak n = 30bir saniyenin altında gerçekleşir.
DLosc

1
@DLosc Fikrini beğendim ve bir tane daha iyi yaptım :)
Sp3000

Güzel! İşte 2 bayt daha:f=lambda n,k=1:sorted([k][n:]or(k>4==k%6and f(n-1,~-k/3)or[])+f(n-1,k*2))
DLosc

@DLosc Ahaha teşekkürler. Yine de yemin ederim ki daha iyi bir kısa devre yolu
olmalı

Bunun ~-gereksiz olduğunu düşünüyorum çünkü tamsayıyı kullanıyorsunuz.
isaacg

5

CJam, 29 26 bayt

Xari{{2*_Cmd8=*2*)}%1-}*$p

Credit, her yinelemeden sonra 1'leri kaldırma fikrinden dolayı @isaacg'a gider, bu da beni doğrudan ve bir tane daha dolaylı olarak iki bayt kurtardı.

CJam tercümanında çevrimiçi olarak deneyin (bir saniyeden daha kısa sürede bitmelidir ).

Nasıl çalışır

Xa       e# Push A := [1].
ri{      e# Read an integer from STDIN and do the following that many times:
  {      e# For each N in A:
    2*   e#     Push I := (N * 2) twice.
    _Cmd e#     Push (I / 12) and (I % 12).
     8=  e#     Push K := (I % 12 == 8).

         e#     (K == 1) if and only if the division ((N - 1) / 3) is exact and
         e#     yields an odd integer. In this case we can compute the quotient 
         e#     as (I / 12) * 2 + 1.

    *2*) e#     Push J := (I / 12) * K * 2 + 1.

         e#     This yields ((N - 1) / 3) when appropriate and 1 otherwise.
  }%     e# Replace N with I and J.
  1-     e# Remove all 1's from A.

         e# This serves three purposes:

         e# 1. Ones have been added as dummy values for inappropriate quotients.

         e# 2. Not allowing 1's in A avoids integers that have already stopped
         e#    from beginning a new cycle. Since looping around has been prevented,
         e#    A now contains all integers of a fixed stopping time.

         e# 3. If A does not contain duplicates, since the maps N -> I and N -> J
         e#      are inyective (exluding image 1) and yield integers of different
         e#      parities, the updated A won't contain duplicates either.

}*       e#
$p       e# print(sort(C))

4

CJam, 35 bayt

1]ri{_"(Z/Y*"3/m*:s:~\L+:L-_&0-}*$p

Açıklama çok yakında. Bu, "oldukça yalındır" yaklaşımdan çok daha hızlı bir sürümüdür (düzenleme geçmişinde görün).

Online Burada deneyin için N = 30hangi anında çevrimiçi sürümünde saniyede çalışır ve Java derleyicisi


Bu daha büyük girdiler için ne kadar sürecek? It should finish in seconds or minutes, not hours or days.
DLosc

Ah, anlıyorum.
Yazdığım

Son sürüm neredeyse anında çalışır.
Doktor,

6
Kodunda bir hata var. Test durumu S=15çalışmıyor.
Jakube,

3

Java 8, 123

x->java.util.stream.LongStream.range(1,(1<<x)+1).filter(i->{int n=0;for(;i>1;n++)i=i%2<1?i/2:3*i+1;return n==x;}).toArray()

Ne zaman x 30'dur, program 15 dakika ve 29 saniye sürer.

Expanded

class Collatz {
    static IntFunction<long[]> f =
            x -> java.util.stream.LongStream.range(1, (1 << x) + 1).filter(i -> {
                int n = 0;
                for (; i > 1; n++)
                    i = i % 2 < 1 ? i / 2 : 3 * i + 1;
                return n == x;
            }).toArray();

    public static void main(String[] args) {
        System.out.println(Arrays.toString(f.apply(15)));
    }
}

Sadece merak ediyorum, bu S = 30 için ne kadar sürüyor?
Geobits

Bu sadece Java 8'de çalışır, doğru mu? javac 1.7.0_79Ubuntu'da kullanmak bana birçok sözdizimi hatası verdi.
DLosc

@DLosc Doğru; Ben postada bunu söyleyeceğim.
Ypnypn

Döngü terminali koşulunu i > 1 && ++n <= x(siz de düşürebilirsiniz n++) sınırlandırmak sadece 5 karakter için daha hızlı görünüyor ... benim için S = 30 için yaklaşık 3 dakika. Ben de dahil edersem, bir dakikadan daha az bir .parallel()
sürede

1

Python 2, 118 bayt

@ Sp3000'in çözümünü gördükten sonra en iyi Python puanına ulaşamayacağımı düşündüm. Ama eğlenceli küçük bir problem gibi görünüyordu, bu yüzden yine de bağımsız bir çözüm denemek istedim:

s={1}
for k in range(input()):
 p,s=s,set()
 for t in p:s.add(2*t);t>4and(t-1)%6==3and s.add((t-1)/3)
print sorted(s)

Boşluğu çıkarmadan önce aynı şey:

s={1}
for k in range(input()):
    p,s=s,set()
    for t in p:
        s.add(2 * t)
        t > 4 and (t - 1) % 6 == 3 and s.add((t - 1) / 3)
print sorted(s)

Bu, geniş kapsamlı bir ilk araştırmanın doğrudan bir uygulamasıdır. Her adımda durma süresi kolan setimiz var ve setteki k + 1her değerin olası öncüllerini tadım adım ekleyerek setin durma süresi ile türetilmesini sağlarız k:

  • 2 * t her zaman olası bir öncüldür.
  • Eğer tolarak bulunmayan tek bir sayı 3 * u + 1olduğu gibi yazılabilirse , o zaman bir öncül de olabilir.u1u

N = 30MacBook Pro'umda çalıştırmak yaklaşık 0.02 saniye sürüyor .


Genelde s.add(x)golf oynamak gereksizdir, çünkü s|={x}bunun yerine genellikle yapabilirsiniz . Ayrıca, parantez ~-xyerine (x+1)tasarruf yerine kullanarak . Ama başka türlü, iyi iş :)
Sp3000

@ Sp3000 Teşekkürler. İkinciyi kolaylıkla değiştiremem s.add()çünkü bu bir ödev olur ve artık ifadenin bir parçası olamaz. İlki için çalışıyor. forSayaçları dayalı döngüler her zaman nazik ayrıntılı yanı vardır. Bir whiledöngü kullanarak onu kısaltabileceğimi düşündüm , ancak tamamen aynı uzunlukta olduğu ortaya çıktı.
Reto Koradi

forDöngü yerine , girişi başka bir şekilde kullanmadığınızdan, muhtemelen exec"..."*input()yerine kullanabilirsiniz :)
Sp3000

1

PHP 5.4+, 178 bayt

İşlev

function c($s,$v=1,$p=[],&$r=[]){$p[]=$v;if(!$s--){return$r[$v][]=$p;}c($s,$v*2,$p,$r);is_int($b=($v-1)/3)&!in_array($b,$p)&$b%2?c($s,$b,$p,$r):0;ksort($r);return array_keys($r);}

Test ve Çıktı

echo "0 - ".implode(',',c(0)).PHP_EOL;
// 0 - 1
echo "1 - ".implode(',',c(1)).PHP_EOL;
// 1 - 2
echo "5 - ".implode(',',c(5)).PHP_EOL;
// 5 - 5,32
echo "9 - ".implode(',',c(9)).PHP_EOL;
// 9 - 12,13,80,84,85,512
echo "15 - ".implode(',',c(15)).PHP_EOL;
// 15 - 22,23,136,138,140,141,150,151,768,832,848,852,853,904,906,908,909,5120,5376,5440,5456,5460,5461,32768

S (30) 0,24 saniyede * çalışır , 732 öğe döndürür. Bir çift

86,87,89,520,522,524,525,528, [ ... ] ,178956928,178956960,178956968,178956970,1073741824

* Ben eklemek zorunda bayt üzerinde tasarruf etmek ksortve array_keysher adımda. Yapabileceğim diğer tek seçenek, çağıran c()ve sonra çağıran array_keysve ksortsonucu bir kez yapan küçük bir sarmalayıcı işlevi yapmaktı . Ancak hala terbiyeli bir şekilde çabuk davrandığım için, düşük bayt sayısı için performans isabeti almaya karar verdim. Doğru sıralama ve işleme olmadan, zaman 0.07 saniyedir. S (30) için ortalama .

Çok fazla ek bayt olmadan, yalnızca bir kez doğru işlem yapmanın akıllıca bir yolu varsa, lütfen bana bildirin! (Numaralarımı dizi tuşları olarak saklıyorum, dolayısıyla kullanımı array_keysve ksort)


0

C dili

#include <stdio.h>
#include <limits.h>    
const int s = 30;

bool f(long i)
{
    int r = 0;
    for(;;)
        if (i < 0 || r > s) return false;
        else if (i == 1) break;
        else{r ++;i = i % 2 ? 3*i + 1 : i/2;}
    return (r==s);
}

void main(){
    for(long i = 1; i < LONG_MAX; i++) if (f(i)) printf("%ld ", i);
}

5
Merhaba ve PPCG'ye hoş geldiniz! Bu bir kod golf yarışması olduğundan, kodunuzu mümkün olduğunca kısa yapmak istersiniz. Ayrıca, lütfen gönderiminize dilin adını ekleyin.
Alex A.

Sizin {}için yaptığım kodunuzu biçimlendirmek için düğmeye basabilirsiniz. Ama Alex'in dediği gibi, lütfen dil adını (C?) Ekleyiniz ve golf oynamayı deneyiniz :) Ama hoş geldiniz!
Sp3000

@ Sp3000, kodu biçimlendirmenize yardımcı olduğunuz için teşekkür ederiz
rüzgarlı

İşlev fdüzgün çalışmıyor. İle s=5bir sürü yanlış sonuç alıyorum. if (r == s)return true;olması gerekir return (r==s), çünkü fne zaman anlamlı hiçbir şey geri dönmeyecek (r < s). Ayrıca, sana beyan gerektiğini düşünüyorum iiçinde folarak longbazı değerler için oldukça hızlı bir şekilde taşar beri.
Dennis,

@Dennis teşekkürler :) olmalıreturn (r==s);
rüzgarlı
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.