Permütasyonlarla Eğlence


17

Kim permütasyonları kesinlikle sevmez, değil mi? Biliyorum, inanılmazlar –– çok eğlenceli!

Peki, neden bu eğlenceyi alıp daha eğlenceli hale getirmiyorsun ?

İşte zorluk:

Tam formda bir girdi verildiğinde: nPrburada nhavuz alınır ve rbu havuzdaki seçimlerin sayısıdır (ve nve rtamsayılardır), tam permütasyon sayısını verir / döndürür. Terminoloji ile biraz paslı olanlar için: Permütasyon, def. 2a .

Ancak, burada meydan okuma devreye giriyor (çok kolay değil):

Permütasyon fonksiyonunuz için herhangi bir yerleşik kütüphane, çerçeve veya yöntem kullanamazsınız. Faktöriyel bir yöntem, permütasyon yöntemi veya herhangi bir tür kullanamazsınız; her şeyi kendin yazmalısın.

Daha fazla açıklama gerekiyorsa, lütfen yorumlarda bana söylemekten çekinmeyin ve derhal buna göre hareket edeceğim.


İşte bir G / Ç örneği:

Örnek fonksiyon permute(String) -> int

Giriş:

permute("3P2")

Çıktı:

6

Bu kod golf, bu yüzden en kısa kod kazanır!


2
Ayy. Bu zorluğun permütasyon grupları üzerinde olacağını düşündüm . Güzel şeyler. Bu da havalı ve permütasyon grupları ile yakından ilişkilidir. Meydan okumayı seviyorum.
Justin

Yerleşik veya kütüphane yöntemi olmadığında permütasyon mu demek istediniz? Dahili splitgirişi adresinde bölmek için kullanabilir miyim P? Dizeyi sayıya dönüştüren bir işleve ne dersiniz?
xnor

3
Cevaplar bunu varsayabilir 0 <= r <= nmi?
Peter Taylor

1
@Dopapp Yani r , n'den büyük değil mi?
Dennis

1
@RetoKoradi - Sanırım çoğu posteri cevaplarını tekrar yapmaya zorlamamak için herhangi bir faktöriyel veya permütasyon yöntemi / fonksiyonu kullanmanıza izin verilmiyor.
Daniel

Yanıtlar:


4

CJam, 15 14 bayt

r~\;~\),>UXt:*

CJam yorumlayıcısında çevrimiçi deneyin .

Nasıl çalışır

r              e# Read a token ("nPr") from STDIN.
 ~             e# Evaluate. This pushes the numbers n, Pi and r on the stack.
  \;           e# Discard Pi.
    ~          e# Take the bitwise NOT of r. Pushes -(r+1).
     \)        e# Increment n.    
       ,       e# Turn n+1 into [0 ... n].
        >      e# Keep only the last r+1 elements.
         UXt   e# Replace the first element with 1.
               e# This avoid dealing with the egde case nP0 separately.
            :* e# Compute their product.

4

Perl, 27 bayt

#!perl -pl61
$\*=$`-$%++for/P/..$'}{

Mesele 4 olarak sayılır, girdi stdin'den alınır.


Örnek Kullanımı

$ echo 3P2 | perl npr.pl
6

$ echo 7P4 | perl npr.pl
840

Ne tür bir seçenek l61?
feersum

@feersum bu ayarlar $\için 1(61 sekizlik char 49).
primo

3

Haskell, 71 66 bayt

p s|(u,_:x)<-span(/='P')s,(n,k)<-(read u,read x)=product[n-k+1..n]

Oldukça basit şeyler: 'P' ye bölün ve ürünü (n-k + 1) ve n arasında alın.

Bir wherecümle yerine desen korumaları kullanma fikirleri için nimi sayesinde , 5 bayt tıraş oldu.


2

Minkolang 0.11 , 13 25 19 bayt

Bunu önerdiği için Sp3000'e teşekkürler !

1nnd3&1N.[d1-]x$*N.

Burada deneyin.

açıklama

1        Push 1
n        Take integer from input (say, n)
n        Take integer from input (say, k); ignores non-numeric characters in the way
d3&1N.   Output 1 if k is 0
[   ]    Loop k times
 d1-     Duplicate top of stack and subtract 1
x        Dump top of stack
$*       Multiply all of it together
N.       Output as integer

Bu Alex'in algoritması ile aynıdır: n P k= n(n-1)(n-2)...(n-k+1).


2

Julia, 63 58 48 bayt

s->((n,r)=map(parse,split(s,"P"));prod(n-r+1:n))

Bu, bir dizeyi kabul eden ve bir tamsayı döndüren adsız bir işlev oluşturur. Bunu aramak için bir ad verin, örn f=s->....

Ungolfed:

function f(s::AbstractString)
    # Get the pool and number of selections as integers
    n, r = map(parse, split(s, "P"))

    # Return the product of each number between n-r+1 and n
    return prod(n-r+1:n)
end

Bu, permütasyon sayısının n ( n -1) ( n -2) ... ( n - k +1) olduğu gerçeğini kullanır .

Glen O sayesinde 10 bayt kurtardı!


Gerek yok Int, böylece kullanabilirsiniz map(parse,...).
Glen O

@GlenO Aklım patladı. IntBu durumda gerekli olduğunu fark etmedim . Çok teşekkürler!
Alex

2

Bash + Linux araçları, 33

jot -s\* ${1#*P} $[${1/P/-}+1]|bc

jot, ile rbaşlayan tamsayılar dizisini üretir n-r+1ve ile ayırır *. Bu ifade bcaritmetik değerlendirme için kullanılır.


1

MATLAB, 54 bayt

[n,r]=strread(input(''),'%dP%d');disp(prod((n-r+1):n))

Daha küçük yapmaya çalıştım, ama MATLAB'ın gerçekten kötü olduğu şeylerden biri de girdi almak. Giriş dizesinden iki sayıyı almak 32 karakter sürer!

Kendini açıklayan kod. %dP%d% D bir tam sayı olduğu girdiyi alın . Bunu nve öğelerine ayırın r. Daha sonra aralığında her tamsayı ürününü gösterir n-r+1için n. İlginçtir, bu xP0, 1'in doğru cevabını vermek için bile çalışır . Bunun nedeni, MATLAB'de prod()boş bir dizinin ürününü denediğinizde işlev 1 döndürmesidir. Her ne zaman rsıfırdır, aralık biz 1 olsun böylece tombala, boş bir dizi olacak.


Bu, Octave ile de mükemmel çalışır . Burada çevrimiçi deneyebilirsiniz .


1

Javascript, 59 57 bayt

s=>(f=(n,k)=>k?(n- --k)*f(n,k):1,f.apply(f,s.split('P')))

1

Java (594 - bayt)

import java.util.*;import java.lang.*;public class Perm {private String a;private static int[] nr=new int[2];private static int sum=1;Scanner in=new Scanner(System.in);public String input(){a=in.nextLine();return a;}public void converter(String a){this.a=a;String b=a.substring(0,1);String c=a.substring(2);nr[0]=Integer.parseInt(b);nr[1]=Integer.parseInt(c);}public int param(){for(int counter=0; counter < nr[1]; counter++){sum=sum*nr[0]--;}return sum;}public static void main(String args[]){Perm a;a=new Perm();String k=a.input();a.converter(k);int ans=a.param();System.out.println(ans);}}

1

J, 23 bayt

^!._1/@(".;._1)@('P'&,)

Anonim bir işlev. Misal:

   f =. ^!._1/@(".;._1)@('P'&,)
   f '10P4'
5040

Açıklama:

       (  ;._1)@('P'&,)   Split over 'P', and on each slice,
        ".                read a number.
      @                   Then,
^!._1/                    fold (/) with the built-in "stope function" (^!.k) for k=1.

Kullandığım stope işlevi yerleşik olarak saymaya sınırlanabilir ... Çarpma operatörünün genelliği ile faktöriyel operatörün özgüllüğü arasında bir yerde bulunur.


1

APL, 23

{{×/⍵↑⍳-⍺}/-⍎¨⍵⊂⍨⍵≠'P'}

Dizeyi argüman olarak alır. Açıklama:

              ⍵⊂⍨⍵≠'P'  ⍝ Split by 'P'.
           -⍎¨          ⍝ Convert to numbers and negate making a vector (−n −r)
 {       }/             ⍝ Reduce it by a defined function, which
      ⍳-⍺               ⍝ makes a vector of numbers from 1 to n (⍺)
    ⍵↑                  ⍝ takes r last elements (⍵←−r)
  ×/                    ⍝ and multiplies them together.

Bu hangi APL? Dyalog kopyamla ilgili bir hata alıyorum.
lirtosiast

1
@ThomasKwa Dyalog'da kullanın ⎕ML←3.
user46915

1

Python 2, 66

def f(s):a,b=map(int,s.split('P'));P=1;exec"P*=a;a-=1;"*b;print P

Oldukça basit. Sayı girişini olarak işler a,b. Çalışan bir ürünü P, ilk bterimleriyle çarpılarak tutar a, a-1, a-2, ....


2
input()Bir hatayla nasıl sonuçlanamadığını göremiyorum .
feersum

@feersum Ben denedim ve gerçekten bir sözdizimi hatası atar.
Alex

Ben "3P2"genellikle tırnak izin verilir gibi girdi alıyordum , ama burada meydan okuma "tam formda bir girdi" diyor, bu yüzden bir dize alan bir işlev olarak değiştirin.
xnor

1

TI-BASIC, 52 bayt

Ans→Str1
expr(sub(Ans,1,⁻1+inString(Ans,"P→P        ;n
1
If expr(Str1                               ;If n^2*r ≠ 0
prod(randIntNoRep(P,P+1-expr(Str1)/P²
Ans

TI-BASIC'in bir "liste ürünü" işlevi vardır, bu nedenle yerleşikler üzerindeki kısıtlamayı aşmak çok zor değildir. Ancak, TI-BASIC boş listeleri desteklemez; bu nedenle

İki sayıyı çıkarmak için, ilk sayıyı bir alt dize olarak çıkarırım. Bu pahalıdır ; tüm ikinci çizgiyi kaplar. Bunu ikinci sayı için tekrar yapmak zorunda kalmaktan kaçınmak için P değişkenini bu sayıya ayarladım ve tüm dizeyi değerlendirip expr(P²'ye böldüm.

Son olarak, iki sayı arasındaki listenin rastgele bir permütasyonunu alıyorum (ikinci sayıya bir tane eklemeye özen göstererek) ve ürünü alıyorum.


1

Ouroboros , 47 45 bayt

Bazıları oldukça çirkin - daha fazla golf olabilir hayal ediyorum.

Sr.r-1(
)s.!+S1+.@@.@\<!@@*Ys.!+*S.!!4*.(sn1(

Ouroboros'taki her kod satırı, kuyruğunu yiyen bir yılanı temsil eder.

Yılan 1

Spaylaşılan yığına geçer. r.rbir sayıyı okur, çoğaltır ve başka bir sayıyı okur. (Nümerik olmayan karakterler Patlanır.) İkisini -çıkartır. Giriş olsaydı 7P2, şimdi var 7, 5paylaşılan yığın. En sonunda,1( yılanın son karakterini yer. Bu talimat göstergesinin açık olduğu karakter olduğundan yılan ölür.

Yılan 2

)silk kez hiçbir şey yapmaz. .!+yılan 2 yığınının üstünü çoğaltır, sıfır olup olmadığını kontrol eder ve eğer eklerse 1. İlk yinelemede, yığın boştur ve sonsuz sıfır içeriyormuş gibi işlem görür, bu nedenle bu1 ; sonraki yinelemelerde, yığın sıfır olmayan bir değer içerir ve bunun bir etkisi yoktur.

Ardından, ürünü hesaplamak için Snumaraya nve sayaca sahip olduğumuz paylaşılan yığına geçer . 1+sayacı artırır. .@@.@\<!her iki sayıyı çoğaltır ve nhala sayaçtan büyük veya ona eşitse 1'i , aksi takdirde 0'ı iter . @@*Ydaha sonra sayacı bu miktarla çarpar ve bir kopyasını yılan 2'nin yığınına çeker.

s.!+Yılan 2'nin yığınına geri döner ve 0 ise üst sayıyı 1'e dönüştürmek ve aksi takdirde aynı tutmak için önceki kodla aynı kodu kullanır. Ardından *sonucu, bu yığın üzerinde oturan kısmi ürünle çarpar.

Şimdi paylaşılan yığına ( S) geri dönüyoruz , sayaç-sıfır ( .) çoğaltıyoruz !!ve sıfır olmayan bir sayacı 1'e çevirmek için iki kez ( ) olumsuzluyoruz. Bunu 4*.(4 ile çarpar, çoğaltır ve yılanın sonu.

  • Durma durumuna ulaşmazsak, yığın üzerinde 4'ümüz var. Sonra dört karakter (yenir ve kontrol kodun başına kadar döngüler. Burada )dört karakteri syeniden yaratır, yılan 2'nin yığınına geri döner ve yürütme devam eder.
  • Sayaç geçtiyse n, yığınta 0 var ve hiçbir şey yenilmiyor. snyılan 2'nin yığınına geçer ve en üst değeri bir sayı olarak verir; sonra 1(son karakteri yer ve ölür.

Sonuç, ürünün (r+1)*(r+2)*...*nhesaplanması ve çıktısıdır.

Denemek

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.