Hitung probabilitas dengan tepat

9

Tugas ini adalah tentang menulis kode untuk menghitung probabilitas dengan tepat. Outputnya harus berupa probabilitas tepat yang ditulis sebagai pecahan dalam bentuk yang paling dikurangi. Itu seharusnya tidak pernah output 4/8melainkan 1/2.

Untuk beberapa bilangan bulat positif n, pertimbangkan string acak seragam panjang 1s dan -1s ndan menyebutnya A. Sekarang digabungkan Adengan nilai pertama. Itu A[1] = A[n+1]jika pengindeksan dari 1. Asekarang memiliki panjang n+1. Sekarang juga pertimbangkan string acak kedua panjang ndengan nnilai pertama -1, 0, atau 1 dengan probabilitas 1 / 4,1 / 2, masing-masing 1/4 dan menyebutnya B.

Sebagai contoh, pertimbangkan n=3. Nilai yang mungkin untuk Adan Bbisa A = [-1,1,1,-1]dan B=[0,1,-1]. Dalam hal ini dua produk dalam adalah 0dan 2.

Sekarang perhatikan produk dalam A[1,...,n]dan Bdan produk dalam A[2,...,n+1]dan B.

Kode Anda harus menampilkan probabilitas bahwa kedua produk dalam adalah nol.

Untuk n=1probabilitas ini jelas 1/2.

Saya tidak keberatan bagaimana nditentukan dalam kode tetapi itu harus sangat sederhana dan jelas cara mengubahnya.

Bahasa dan perpustakaan

Anda dapat menggunakan bahasa dan perpustakaan apa saja yang Anda suka. Saya ingin menjalankan kode Anda jadi harap sertakan penjelasan lengkap tentang cara menjalankan / kompilasi kode Anda di linux jika memungkinkan.

Martin Ender
sumber
2
Kasus uji untuk beberapa yang pertama nakan sangat membantu. Mungkin juga contoh eksplisit dari A, B dan dua produk dalam mungkin membantu.
Martin Ender
Jika kita memilih untuk men-harcode integer, apakah n=4dihitung sebagai nol, dua atau tiga byte? Apakah hasilnya harus persis a/b atau akan [a b], mis., Diizinkan?
Dennis
@ Dennis Ini harus tepat. Jika Anda meng-hardcode integer, apakah saya hanya perlu mengubahnya di satu tempat untuk diubah n? Kalau tidak, saya pikir itu tidak diperbolehkan.
Ya, program saya hanya menggunakan integer satu kali untuk menghitung daya kartesius. Yang lainnya diturunkan dari array yang dihasilkan.
Dennis

Jawaban:

7

Pyth, 48 47 46 44 byte

K,smlf!|Fms*Vd.>Tk2^,1_1Q^+0tM3Q^8Qj\//RiFKK

Cobalah online: Peragaan

Versi online mungkin tidak menghitung n=6. Di laptop saya (versi offline) dibutuhkan sekitar 45 detik.

Pendekatan kekerasan.

Penjelasan:

smlf!|Fms*Vd.>Tk2^,1_1Q^+0tM3Q   implicit: Q = input number
                          tM3    the list [-1, 0, 1]
                        +0       add zero, results in [0, -1, 0, 1]
                       ^     Q   all possible lists of length Q using these elements
 m                               map each list d (B in Lembik's notation) to:
                  ,1_1              the list [1, -1]
                 ^    Q             all possible lists of length Q
   f                                filter for lists T (A in Lembik's notation),
                                    which satisfy:
       m        2                      map each k in [0, 1] to:
        s*Vd.>Tk                          scalar-product d*(shifted T by k)
    !|F                                not or (True if both scalar-products are 0)      
  l                                 determine the length                
s                                add all possibilities at the end

K,...^8QQj\//RiFKK   
 ,...^8Q             the list [result of above, 8^Q]
K                    store it in K
              iFK    determine the gcd of the numbers in K
            /R   K   divide the numbers in K by the gcd
         j\/         join the two numbers by "/" and print
Jakube
sumber
dang, lupakan soal gcd, tahu ada sesuatu yang aku rindukan
Maltysen
+0r1_2lebih pendek dari /R2r2_2.
isaacg
Saya pikir adil itu harus menjadi versi 89/512 yang Anda hitung.
@Lembik Ok Mengubahnya.
Jakube
Harus saya akui, tidak pernah terpikir oleh saya bahwa ini bisa dilakukan dalam 47 karakter!
8

Mathematica, 159 100 87 86 85 byte

n=3;1-Mean@Sign[##&@@Norm/@({1,0,0,-1}~t~n.Partition[#,2,1,1])&/@{1,-1}~(t=Tuples)~n]

Untuk mengubah, ncukup ubah definisi variabel di awal.

Karena ini kekuatan kasar, ini cukup lambat, tetapi inilah delapan hasil pertama:

n   P(n)
1   1/2
2   3/8
3   7/32
4   89/512
5   269/2048
6   903/8192
7   3035/32768
8   169801/2097152

Yang terakhir sudah mengambil 231 detik dan runtime sangat eksponensial.

Penjelasan

Seperti yang saya katakan itu brute force. Pada dasarnya, saya hanya menghitung semua yang mungkin Adan B, menghitung dua produk titik untuk setiap pasangan yang memungkinkan dan kemudian menemukan sebagian kecil dari pasangan yang menghasilkan {0, 0}. Combinatorics dan fungsi aljabar linear matematika cukup membantu dalam bermain golf ini:

{1,-1}~(t=Tuples)~n

Ini menghasilkan semua n-tupel yang mengandung 1atau -1, yaitu semua yang mungkin A. Untuk n = 3itu adalah:

{{1, 1, 1}, 
 {1, 1, -1}, 
 {1, -1, 1}, 
 {1, -1, -1}, 
 {-1, 1, 1}, 
 {-1, 1, -1}, 
 {-1, -1, 1}, 
 {-1, -1, -1}}

Untuk menghitung, Bkami melakukan hal yang hampir sama:

{1,0,0,-1}~t~n

Dengan mengulangi 0, kami duplikat setiap tupel untuk setiap 0mengandung, sehingga membuat 0dua kali lebih mungkin sebagai 1atau -1. Sekali lagi menggunakan n = 3sebagai contoh:

{{-1, -1, -1},
 {-1, -1, 0}, {-1, -1, 0},
 {-1, -1, 1},
 {-1, 0, -1}, {-1, 0, -1},
 {-1, 0, 0}, {-1, 0, 0}, {-1, 0, 0}, {-1, 0, 0},
 {-1, 0, 1}, {-1, 0, 1},
 {-1, 1, -1},
 {-1, 1, 0}, {-1, 1, 0},
 {-1, 1, 1},
 {0, -1, -1}, {0, -1, -1},
 {0, -1, 0}, {0, -1, 0}, {0, -1, 0}, {0, -1, 0},
 {0, -1, 1}, {0, -1, 1},
 {0, 0, -1}, {0, 0, -1}, {0, 0, -1}, {0, 0, -1},
 {0, 0, 0}, {0, 0, 0}, {0, 0, 0}, {0, 0, 0}, {0, 0, 0}, {0, 0, 0}, {0, 0, 0}, {0, 0, 0},
 {0, 0, 1}, {0, 0, 1}, {0, 0, 1}, {0, 0, 1},
 {0, 1, -1}, {0, 1, -1},
 {0, 1, 0}, {0, 1, 0}, {0, 1, 0}, {0, 1, 0},
 {0, 1, 1}, {0, 1, 1},
 {1, -1, -1},
 {1, -1, 0}, {1, -1, 0},
 {1, -1, 1},
 {1, 0, -1}, {1, 0, -1},
 {1, 0, 0}, {1, 0, 0}, {1, 0, 0}, {1, 0, 0},
 {1, 0, 1}, {1, 0, 1},
 {1, 1, -1},
 {1, 1, 0}, {1, 1, 0},
 {1, 1, 1}}

Sekarang, untuk setiap kemungkinan A, kami ingin produk titik dari masing-masing yang mungkin B, baik dengan A[1 .. n]dan A[2 .. n+1]. Misalnya jika saat ini kami Aadalah {1, 1, -1}, kami ingin dot produk dengan baik {1, 1, -1}dan dengan {1, -1, 1}. Karena semua kita Bsudah dengan nyaman baris dari matriks, kami ingin dua sublists Asebagai kolom dari matriks lain, sehingga kami dapat menghitung produk titik sederhana di antara mereka. Tetapi transposing {{1, 1, -1}, {1, -1, 1}}hanya memberikan {{1, 1}, {1, -1}, {-1, 1}}yang hanya daftar semua sub-siklik 2-elemen dari A. Itulah yang dilakukan:

Partition[#,2,1,1]

Jadi kami menghitungnya dan mengambil produk titik dengan daftar kami B. Karena sekarang kami mendapatkan daftar bersarang (karena setiap kemungkinan Amenghasilkan vektor terpisah), kami meratakannya dengan ##&@@.

Untuk mengetahui apakah suatu pasangan {x, y}adalah {0, 0}kita menghitung di Sign[Norm[{x,y}]] mana Normmemberi √(x²+y²). Ini memberi 0atau 1.

Akhirnya, karena kita sekarang hanya ingin mengetahui fraksi 1s dalam daftar 0s dan 1s semua yang kita butuhkan adalah rata-rata aritmatika dari daftar. Namun, ini menghasilkan probabilitas kedua produk setidaknya satu titik menjadi nol, jadi kami kurangi dari itu 1untuk mendapatkan hasil yang diinginkan.

Martin Ender
sumber
6

Pyth - 65 55 byte

Bug diperbaiki dengan pengurangan fraksi dengan biaya satu byte.

Menggunakan pendekatan brute force, dan bisa bermain golf sangat, tetapi hanya ingin mendapatkan sesuatu di luar sana. Sangat lambat

*F-KP/Jmms*Vked,thdPhd*makhk^,1_1Q^[1ZZ_1)Q,ZZ2/lJ^2/K2

Menggunakan produk Cartesian untuk menghasilkan keduanya Adan B, melakukan probabilitas variabel dengan membuat 0muncul dua kali dalam daftar sumber dan kemudian menghitung yang produk dalam nol. Produk dalam dipermudah oleh Vgula sintaksis ectorization. Menyederhanakan fraksi membuat saya takut pada awalnya, tetapi cukup mudah dengan Pfungsi Factorization rime dan kesadaran bahwa kita hanya perlu mengurangi dengan kekuatan 2.

Cobalah online di sini .

Maltysen
sumber
Bagaimana saya berubah n?
@Lembik Program Pyth meminta input pengguna, yang ditentukan dalam kotak teks kedua (Jika Anda menggunakan kompiler online).
Jakube
@ Jakube Oh terima kasih! Dan tampaknya benar-benar berfungsi juga :)
6

CJam, 58 57 54 51 46 byte

WX]m*Zm*_{~.+2,@fm<\f.*::+0-!},,__~)&:T/'/@,T/

Untuk menjalankannya, masukkan bilangan bulat yang diinginkan antara WX]dan m*.

Terima kasih kepada @ jimmy23013 untuk bit magic dan untuk bermain golf 5 byte!

Cobalah online di penerjemah CJam .

Ide

Sebagian besar jawaban ini mudah, tetapi menggunakan dua trik:

  • Alih-alih memasangkan semua vektor {-1, 1} n dengan semua vektor {-1, 0, 1} n dengan probabilitas yang diinginkan, ia menghitung jumlah triplet vektor dalam {-1, 1} n yang memenuhi suatu kondisi tertentu.

    Jika kita menambahkan dua vektor terakhir dari triplet, hasilnya akan menjadi vektor {-2, 0, 2} n .

    Karena (-1) + 1 = 0 = 1 + (-1) , 0 s akan muncul dua kali lebih sering dari -2 s dan 2 s.

    Membagi setiap komponen dengan 2 akan menghasilkan vektor {-1, 0, 1} n dengan probabilitas yang diinginkan.

    Karena kami hanya tertarik jika produk skalar 0 atau tidak, kami dapat melewati divisi dengan 2 .

  • Setelah menghitung semua kembar tiga yang memenuhi kondisi pertanyaan dan jumlah total kembar tiga, kita harus mengurangi fraksi yang dihasilkan.

    Alih-alih menghitung GCD dari kedua angka, karena penyebut akan selalu menjadi kekuatan 2, cukup untuk membagi kedua angka dengan kekuatan tertinggi 2 yang membagi pembilang.

    Untuk mendapatkan kekuatan tertinggi 2 yang membagi x , kita dapat mengambil bitwise AND dari x dan ~ x + 1 .

    ~ x membalikkan semua bit x , jadi semua trailing 0 s menjadi 1 s. Dengan menambahkan 1 ke ~ x , mereka 1 s akan kembali menjadi 0 dan yang terakhir 1 di ~ x + 1 akan cocok terakhir 1 di x .

    Semua bit lainnya baik baik 0 dari yang berbeda, sehingga bitwise DAN mengembalikan bilangan bulat yang terdiri dari yang terakhir 1 dari x dan semua 0 s yang mengikutinya. Ini adalah kekuatan tertinggi 2 yang membagi x .

Kode

WX]    e# Push the array [-1 1].
       e# Insert N here.
m*     e# Cartesian product: Push the array of all vectors of {-1,1}^N.
Zm*    e# Cartesian product: Push the array of all triplets of these vectors.
_      e# Copy the array.
{      e# Filter; for each triplet of vectors U, V and W in {-1,1}^N:
  ~    e#   Dump U, V and W on the stack.
  .+   e#   Compute X := V + W, a vector of {-2,0,2}^N, where each component is
       e#   zero with probability 1/2.
  2,@  e#   Push [0 1]. Rotate U on top of it.
  fm<  e#   Push [U U'], where U' is U rotated one dimension to the left.
  \f.* e#   Push [U*X and U'*X], where * denotes the vectorized product.
  ::+  e#   Add the components of both products.
  0-   e#   Remove zeroes.
       e#   Push the logical NOT of the array.
},     e#   If the array was empty, keep the triplet.
,      e# Push X, the length of the filtered array.
__~)&  e# Push X & ~X + 1.
:T     e# Save the result in T and divide X by T.
'/     e# Push a slash.
@,T/   e# Dividet he length of the unfiltered array by T.
Dennis
sumber
WX]m*Zm*_{~.+2,@fm<\f.*::+0-!},,__W*&:T/'/@,T/.
jimmy23013
@ jimmy23013: Itu sedikit sihir yang mengesankan. Terima kasih!
Dennis