Eşsiz primerlerin kombinatoryal ürünleri


21

Sorun bildirimi

Bir dizi benzersiz, ardışık primer seti (zorunlu olarak 2 içermeyen) verilirse, bu primerlerin birinci güçlerinin tüm kombinasyonlarının ürünlerini üretir - örneğin, tekrar yok - ve ayrıca 1. Örneğin, set {2, 3, 5 7}, {1, 2, 3, 5, 6, 7, 10, 14, 15, 21, 30, 35, 42, 70, 105, 210} üretiyorsunuz çünkü:

  1  =  1
  2  =  2
  3  =  3
  5  =  5
  6  =  2 x 3
  7  =  7
 10  =  2 x 5
 14  =  2 x 7
 15  =  3 x 5
 21  =  3 x 7
 30  =  2 x 3 x 5
 35  =  5 x 7
 42  =  2 x 3 x 7
 70  =  2 x 5 x 7
105  =  3 x 5 x 7
210  =  2 x 3 x 5 x 7

Girdi kümenizin kardinalitesi k ise, bunun çıktı kümenizde 2 ^ k üye vereceğini unutmayın.

Kurallar / Koşullar

  1. Herhangi bir dili kullanabilirsiniz. Kaynak kodun en küçük karakter sayımını hedefleyin.
  2. Çözümünüz ya tam bir program ya da tam bir işlev olmalıdır. İşlev isimsiz olabilir (eğer diliniz isimsiz işlevleri destekliyorsa).
  3. Çözümünüz en az 2 ^ 31 ürüne kadar destek verebilmelidir. Ürününü temsil etmek için çok büyük sayılar iletilirse tamsayı taşması algılaması veya işlenmesi konusunda endişelenmeyin. Ancak, lütfen hesaplamalarınızın sınırlarını belirtiniz.
  4. Bir listeyi veya bir seti kabul edip bir liste veya bir set oluşturabilirsiniz. Girişin sıralandığını varsayabilir, ancak sıralı çıktı üretmek zorunda değilsiniz.

Arka fon

Bu ne zaman veya neden yararlıdır? Çok kullanışlı bir yer, Kare Formlar Faktorizasyonu olarak bilinen bir tamsayı faktörü algoritmasında paralel olarak yarışacak bir çarpanlar tablosu oluşturmaktır.. Orada, denediğiniz her garip çarpan, algoritmanın başarısız olma olasılığını (bir faktör bulma) sert yarıçaplarda yaklaşık% 50 azaltır. Bu nedenle, paralel olarak yarışacak 16 deneme çarpanı üreten {3, 5, 7, 11} üretim primerleri seti ile algoritma, zor yarı devrelerde zamanın yaklaşık 2 ila 16'sında başarısız olur. Asallar listesine 13 eklenmesi, 32 deneme çarpanı kümesi üreterek, başarısız olma şansını yaklaşık olarak 2 ^ 32'ye düşürür ve sonuçta hesaplama masrafı olmadan sonuçta büyük bir iyileşme sağlar (çünkü paralel olarak iki kat çarpıştığında, ortalama hala aynı toplam adımda cevabı bulur.

Yanıtlar:


18

Saf Bash, 32 bayt

eval echo \$[{1,${1// /\}*{1,}}]

Komut satırı argümanı olarak iletilen giriş listesini (ayrılmış tek boşluk) okur.

Üç farklı kabuk açılımı kullanılır:

  1. ${1// /\}*{1,}a, parametre genişleme boşluklar yerine 2 3 5 7ile }*{1,elde 2}*{1,3}*{1,5}*{1,7. \$[{1,ve }]sırasıyla sırasıyla başlangıç ​​ve bitişe eklenir \$[{1,2}*{1,3}*{1,5}*{1,7}]. \$[Ters eğik çizgi bulunan bu aşamada aritmetik yapmak girişimlerini önlemektir.
  2. \$[{1,2}*{1,3}*{1,5}*{1,7}]Bir olan ayracı genişleme . Çünkü ayracı genişleme tipik parametre genişleme önce olur , biz kullanmak zorunda kullanmak evalilk gerçekleşmesi parametre genişlemesini zorlamak için. Brace genişlemesinin sonucu $[1*1*1*1] $[1*1*1*7] $[1*1*5*1] ... $[2*3*5*7].
  3. $[1*1*1*1] $[1*1*1*7] $[1*1*5*1] ... $[2*3*5*7]Aritmetik açılımların bir listesidir ve daha sonra ihtiyaç duyduğumuz sayıların listesini vermek için değerlendirilir.

Çıktı:

$ ./comboprime.sh "2 3 5 7"
1 7 5 35 3 21 15 105 2 14 10 70 6 42 30 210
$

3
Zihin ... şişmiş ... vay!
Todd Lehman

Wtf ... anlıyorum1 0
username.ak

@ username.ak Girdiniz nedir? Nasıl giriyorsunuz (komut satırı mı?). Hangi bash sürümünü kullanıyorsunuz? bash --version
Dijital Travma

12

CJam, 13 bayt

1aq~{1$f*+}/p

STDIN'den bir dizi okur (örn [2 3 5 7].). Çevrimiçi deneyin.

Anonim bir işlev aynı bayt sayısına sahip olur:

{1a\{1$f*+}/}

Örnek çalışma

$ cjam <(echo '1aq~{1$f*+}/p') <<< '[]'
[1]
$ cjam <(echo '1aq~{1$f*+}/p') <<< '[2 3 5 7]'
[1 2 3 6 5 10 15 30 7 14 21 42 35 70 105 210]

Nasıl çalışır

1a               " Push R := [1].              ";
  q~             " Read an array A from STDIN. ";
    {     }/     " For each a ∊ A:             ";
     1$f*+       "     R += { ra : r ∊ R }     ";
            p    " Print.                      ";

4
Vay, bu tüm alt grupları yinelemenin akıllı bir yolu.
Martin Ender

9

Haskell, 22

çözüm anonim bir işlevdir:

map product.mapM(:[1])

örnek kullanım:

*Main> map product.mapM(:[1]) $ [2,3,5]
[30,6,10,2,15,3,5,1]

açıklama:
(:[1]) bir sayı verilen xlisteyi döndüren bir fonksiyondur [x,1].
mapM(:[1])bir sayı listesi verilen, işlevi (:[1])üstlerindeki işlevi gösteren ve her listeden bir öğe seçmek için mümkün olan her yolu veren bir işlevdir . örneğin, mapM(:[1]) $ [3,4]ilk önce alacağınız işlevi eşler [[3,1] , [4,1]]. sonra olası seçenekler [3,4](her ikisinin de ilk sayısını seçmek) [3,1] [1,4]ve [1,1]böylece geri döner [[3,4],[3,1],[1,4],[1,1]].

daha sonra map producttüm seçimlerin üzerinden eşler ve istenen çıktı olan ürünlerini döndürür.

bu işlev, türünde, her tür sayı üzerinde çalışabileceği için polimorfiktir. bir listesini girebildiniz Intve sonuç bir liste olurdu ancak bir tür listesine Intde uygulanabilirIntegerve bir listesini döndür Integer. bu, taşma davranışının bu işlev tarafından değil, girdi türü tarafından belirtildiği anlamına gelir (yay Haskell'in ifade tipi sistemi :))


Güzel! Sayı boyutunda herhangi bir sınır var mı?
Todd Lehman

1
@ToddLehman hayır. Varsayılan sayısal tür, Integersınırsız bir tamsayı türüdür. Ayrıca Int, 32-bit bir tamsayı var, ama bu çoğunlukla sadece eski bir şey.
John Dvorak

@JanDvorak pratikte evet ama tip sisteminden söz etmemeyi çok seviyorum :). Dikkat edilmesi gereken bir başka şey de, anonim olması, onu nasıl kullandığınızla ilgili olduğudur, çünkü monomorfizm kısıtlaması bazı durumlarda geçerli olabilir.
Gurur haskeller 21:14

8

Mathematica, 18 17 bayt

1##&@@@Subsets@#&

Bu isimsiz bir işlev. Gibi ara

1##&@@@Subsets@#&[{2,3,5,7}]

Martin de kısa sürede cevap vermiş!
Todd Lehman

@ToddLehman Şimdi bunu yenen J cevabını bekleyelim. ;)
Martin Ender

1
Mathematica kapalı kaynak olmasaydı, birileri golflü bir versiyon yazabilirdi. ×@@@𝒫@#yenilmez olmalı
Dennis,

@Dennis Wolfram Dil belirtimi Mathematica'dan bağımsız olarak kullanılabilir ve bir veya iki (eksik) açık kaynaklı uygulama olduğunu düşünüyorum. Unicode-aliased bir Mathematica sürümü oluşturmak birkaç kez önerildi, ancak PPCG'de çok iyi karşılanacağını sanmıyorum. ^^
Martin Ender

2
@ MartinBüttner Sizi beklettiğim için özür dileme: (*/@#~2#:@i.@^#)J'de 16 karakter;)
algorithmshark

4

Güncelleme: C (işlev f), 92

Bir fonksiyon olarak bile, bu hala en uzun giriş burası. İlk defa, C'de bir işlev argümanı olarak bilinmeyen bir uzunluğa sahip bir diziyi geçirdim ve görünüşe göre, bir C işlevinin kendisine iletilen bir dizinin uzunluğunu bilmesinin bir yolu yok, çünkü argüman bir işaretçi olarak geçirilir ( kullanılan sözdizimine bakılmaksızın). Dolayısıyla, uzunluğu belirtmek için ikinci bir argüman gerekir.

Çıkışı stdout'ta tuttum, çünkü bir tamsayı dizisi ayarlamak ve onu döndürmek neredeyse kesinlikle daha uzun olacaktı.

İpuçları için Dennis'e teşekkürler.

fAşağıdaki test programlarında fonksiyona (gereksiz beyaz boşluk hariç 92 karakter) bakın.

Printf üzerinden çıktı

j;

f(int c,int*x){
  int p=1,i;
  for(i=c<<c;i--;p=i%c?p:!!printf("%d ",p))p*=(i/c>>i%c)&1?1:x[i%c];
}

main(int d,char**v){
  d--;
  int y[d];
  for(j=d;j--;)y[j]=atoi(v[j+1]);
  f(d,y);
}

Dizi işaretçisi üzerinden çıktı

j,q[512];

f(int c,int*x,int*p){
    for(int i=-1;++i-(c<<c);p[i/c]*=(i/c>>i%c)&1?1:x[i%c])i%c||(p[i/c]=1);
}

main(int d,char**v){
  d--;
  int y[d];
  for(j=d;j--;)y[j]=atoi(v[j+1]);
  f(d,y,q);
  for(j=1<<d;j--;)printf("%d ",q[j]);
}

C (program), 108

Gereksiz boşluklar hariç.

p=1,i;
main(int c,char**v){
  c-=1;
  for(i=c<<c;i--;i%c||(printf("%d ",p),p=1))(i/c>>i%c)&1||(p*=atoi(v[i%c+1]));
}

Komut satırından giriş, stdout çıkışına. C burada kazanmayacak, ama belki yarın bir işleve dönüşmeyi deneyeceğim.

Temel olarak 1<<c, her bir bit i/c, üründe belirli bir asalın varlığı veya yokluğu ile ilişkilendirilen tüm prim kombinasyonları boyunca yinelenir . "İç döngü" i%cdeğerine göre çarpılarak asal üzerinden çalışır, i/c.sonra i%c, ürün bir sonraki "dış" yineleme için 1 olarak ayarlanır çıkış ulaşır 0'dır.

Merakla, printf("%d ",p,p=1)çalışmıyor Bu değer, bir kullanıldığında Garip davranış gördük ilk kez olmuyor (her zaman bir 1. yazdırır) printfve aynı parantez içinde sonradan atanan. Bu durumda, ikinci virgül argüman ayırıcı olarak değil, operatör olarak değerlendirilebilir.

kullanım

$ ./a 2 3 5 7
1 2 3 6 5 10 15 30 7 14 21 42 35 70 105 210

C, bağımsız değişkenlerin değerlendirildiği sırayı titizlikle tanımlamaz. Özellikle, birçok C işlevi çağrısının sağdan sola değerlendirilen bağımsız değişkenleri vardır.
COTO

Bölüm 6.5.2.2 itibaren TC 3: ISO / IEC 9899 : Gerçek argümanlarla fonksiyon designator, gerçek tartışmaların değerlendirilmesi amacıyla ve subexpressions belirtilmemiş olan [.] Yani, bir işlev siparişini hangi derleyici kadardır Argümanlar değerlendirilir. İle -Wsequence-pointya da -Wall, GCC şikayet edecektir.
Dennis,

1. Değişebilirsin c-=1için c--hatta kullanmak i=--c<<csize UB sakıncası yoksa (o GCC ile çalışmak görünüyor). 2. Her iki kullanımları ||üçlü operatörleri ile değiştirilebilir: p=i%c?p:!!printf("%d ",p)vep*=(i/c>>i%c)&1?1:atoi(v[i%c+1])
Dennis

@Dennis İpuçları için teşekkürler! Yatmadan hemen önce gönderdim, böylece programı çalıştırdım. c-=1bu kadar basit bir golf oyunu kaçırmamalıydım, ama hızlı bir hata düzeltmesi yapıldı çünkü unutmuşum ki argv'da bir tane daha dize varmış (program adı.) i=..c<<cGCC / cygwin'de çalışıyor ama orijinalimden ayrıldım program olduğu gibi ve bir işleve taşınır. Bu yüzden sizeoffonksiyon argümanları olarak geçen diziler üzerinde çalışmadığını öğrendim . Üçlü operatörlere yönelik önerilerinizi bu fonksiyona dahil ettik. Bir dizi döndürmek için kısa bir yol göremediğim için stdout'a çıktı ile yapıştım.
Seviye Nehri St

Evet, işlev argümanları işaretçilere bozulurken diziler geçti. - Sonuçları bir işlev parametresi olarak içermesi gereken diziye bir gösterici iletmek C de nadir değildir. Sorusu sadece büyüklüğü 512 dizisi iletebilirsiniz böylece, ürünlerin 2 ^ 31 daha küçük olduğunu varsayabiliriz diyor
Dennis

3

Haskell, 27 bayt

Bu, @ sudo'nun CJam adının adsız bir işlev olarak verdiği Haskell uygulamasıdır. @ Gururlu haskeller'in müthiş Haskell çözümünü yenemez, ama yine de buraya bırakacağım.

foldr((=<<)(++).map.(*))[1]

Açıklama: foldr bir ikili fonksiyon, bir değer ve bir liste alır. Daha sonra, bu gibi bir fonksiyonunun bir uygulama tarafından listedeki her dezavantajları hücre ve değeri listesinin sonuna, yerine geçer: foldr f v [a,b,c] == f a (f b (f c v)). Bizim değerimiz tek elemanlı bir liste 1ve ikili fonksiyondur f = (=<<)(++).map.(*). Şimdi, fbir sayı alır n, bir işlev yapar (n*)ile çarpar o n, ondan bir işlev yapar g = map(n*)bir listesinin tüm elemanlarına bu işlevi uygular ve beslemeleri o işlevin (=<<)(++). Burada, (++)birleştirme işlevi olduğunu ve (=<<)bir monadic bağlama bu durumda alır, (++)ve g, uygular ve bir liste halinde götüren bir işlevi verirg Bir kopyasına ve ikisini birleştirir.

Kısacası: ile başlayın [1]ve ngiriş listesindeki her numara için geçerli listenin bir kopyasını alın, her şeyi çarpın ve mevcut listeye nekleyin.


3

Python: 55 karakter

f=lambda l:l and[x*l[0]for x in f(l[1:])]+f(l[1:])or[1]

Sırasıyla her numarayı dahil etmeyi veya hariç tutmayı seçerek ürünleri tekrar tekrar üretir.


Özyinelemeli çözüm! Güzel!
Todd Lehman

andToplamı tersi yönde yazarsanız, sonradan alanı bırakabileceğinizi düşünüyorum.
mathmandan

@mathmandan Yup, işe yarıyor, teşekkürler.
xnor

3

PARI / GP , 26 bayt

v->divisors(factorback(v))

Uzun versiyonlar arasında

v->divisors(prod(i=1,#v,v[i]))

(30 bayt) ve

v->divisors(fold((x,y)->x*y,v))

(31 bayt).

Girdi küme yerine bir çarpanlara ayırma matrisi olsaydı , 18 bayt divisorstek başına kullanarak kaydedilebileceğini unutmayın . Fakat bir setin bir faktoring matrisine dönüştürülmesi 18 bayttan daha uzun sürüyor gibi görünüyor. (Bunu v->concat(Mat(v~),Mat(vectorv(#v,i,1)))çarparak ve yeniden çarpanlara ayırarak doğrudan 39 bayt veya 24 baytta v->factor(factorback(v))yapabilirim, herkes daha iyisini yapabilir mi?)


2

Adaçayı - 36 34

Temel olarak , eğer doğru anladıysam , Martin Büttner'ın çözümü ile aynı . Bir yorumda bahsettiğim gibi, bir cevap olarak da gönderebilirim.

lambda A:map(prod,Combinations(A))

Bu isimsiz bir fonksiyondur, örneğin şu şekilde çağrılabilir:

(lambda A:map(prod,Combinations(A)))([2,3,5,7])

1
2
byte'ı

2

J (20)

Bu, beklediğimden veya beklediğimden daha uzun sürdü.

*/@:^"1#:@i.@(2&^)@#

Kullanımı:

    f=:*/@:^"1#:@i.@(2&^)@#
    f 2 3 5 7
1 7 5 35 3 21 15 105 2 14 10 70 6 42 30 210

Bu sadece asal sayılar için değil, herhangi bir sayı kümesi için çalışır. Ayrıca asal sürece dizi ekine sahip olduğu sürece, sınırsız büyüklükte olabilir x:2 3 5 7x


*/@#~2#:@i.@^#14 bayt için bir alternatiftir.
mil,


1

R, 56 bayt

r=1;for(i in 1:length(s))r=c(r,apply(combn(s,i),2,prod))

Burada kümenin (ve bir listenin) olduğunu düşünüyorum. Daha da kısa yapılabileceğinden eminim. Göreceğiz.


1

PHP, 97 Bayt

<?for(;$i++<array_product($a=$_GET[a]);){$t=$i;foreach($a as$d)$t%$d?:$t/=$d;if($t<2)echo"$i\n";}
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.