精确计算概率


9

此任务是关于编写代码以准确计算概率。输出应该是精确的概率,以其最大简化形式的分数表示。那是它永远不应该输出4/8,而应该1/2

对于某个正整数n,请考虑一个长度为1s和-1s的均匀随机字符串,n并将其称为A。现在将A其串联为第一个值。就是说A[1] = A[n+1]从1 A开始的索引 现在具有length n+1。现在还考虑长度的第二随机串n,其第一n值是-1,0或1的概率是1 / 4,1 / 2,1/4每并调用它B.

例如,考虑n=3。对于可能的值A,并B可能会A = [-1,1,1,-1]B=[0,1,-1]。在这种情况下,两个内积是02

现在考虑的内积A[1,...,n]B和的内积A[2,...,n+1]B

您的代码必须输出两个内积均为零的概率。

对于n=1这种可能性显然是1/2

我不介意n代码中的指定方式,但是如何更改它应该非常简单明了。

语言和图书馆

您可以使用任何喜欢的语言和库。我想运行您的代码,因此请尽可能提供有关如何在Linux中运行/编译代码的完整说明。


2
前几个测试用例n会有所帮助。也可能是A,B和两个内积的明确示例可能有所帮助。
Martin Ender 2015年

如果我们选择对整数进行编码,是否n=4算作零,两个或三个字节?输出必须是精确的 a/b还是将[a b]被允许?
丹尼斯

@丹尼斯必须准确。如果您对整数进行硬编码,我是否只需要在一个地方更改就可以更改n?否则,我认为这是不允许的。

是的,我的程序只使用一次整数来计算笛卡尔乘方。其他所有内容均来自结果数组。
丹尼斯

Answers:


7

Pyth,48 47 46 44字节

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

在线尝试:演示

在线版本可能无法计算n=6。在我的笔记本电脑(脱机版本)上,大约需要45秒。

蛮力法。

说明:

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

dang,忘记了gcd,知道我错过了一些东西
Maltysen,2015年

+0r1_2比短/R2r2_2
isaacg 2015年

我认为应该算是您认为的89/512版本。

@Lembik Ok更改了它。
Jakube 2015年

我必须承认,这从来没有想过可以用47个字符完成!

8

Mathematica,159 100 87 86 85字节

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

要更改,n只需在开始时更改变量定义。

由于它是蛮力的,所以它相当慢,但是这里是前八个结果:

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

最后一个已经花费了231秒,运行时间是指数级的。

说明

如我所说,这是蛮力。本质上,我只是列举所有可能的值,AB为每个可能的对计算两个点积,然后找出产生的对的分数{0, 0}。Mathematica的组合函数和线性代数函数在打高尔夫球方面非常有帮助:

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

这会生成包含1-1即all的所有n元组A。为此n = 3是:

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

为了进行计算,B我们几乎执行相同的操作:

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

通过重复0,我们为每个元组0包含的每个元组重复一个,从而使之0成为1或的两倍-1。再次使用n = 3示例:

{{-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}}

现在,对于每种可能A,我们都希望B使用A[1 .. n]和的每种可能的点积A[2 .. n+1]。例如,如果我们现在A是的话{1, 1, -1},我们希望既有{1, 1, -1}和又有的点积{1, -1, 1}。由于我们所有人B都已经方便地成为矩阵的行,因此我们希望将的两个子列表A作为另一个矩阵的列,以便我们可以计算它们之间的简单点积。但是转置{{1, 1, -1}, {1, -1, 1}}只是给出了{{1, 1}, {1, -1}, {-1, 1}},而这只是的所有2元素循环子列表的列表A。这就是这样做的:

Partition[#,2,1,1]

因此,我们对其进行了计算,并将点乘积与的列表一起使用B。由于我们现在获得了一个嵌套列表(因为每种可能都A产生了一个单独的向量),因此我们用展平了它们##&@@

要找出是否一对{x, y}{0, 0}我们计算Sign[Norm[{x,y}]] 其中Norm给人√(x²+y²)。这给出01

最后,由于我们现在只想知道s和s 1列表中0s 的分数,1所以我们所需要的只是列表的算术平均值。但是,这产生了至少一个点积都为非零的可能性,因此我们将其减去1以获得期望的结果。


6

Pyth- 65 55字节

修复了以一字节为代价减少分数的错误。

使用蛮力方法,可以打很多球,但只是想从那里得到一些东西。非常慢

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

它使用笛卡尔乘积来生成AB,并通过使变量0在源列表中出现两次来进行变量概率的计算,然后将内积归零。内化通过V句法化糖变得容易。简化分数起初让我感到害怕,但是使用Prime因数分解函数和意识到我们只需要减少2的幂就可以很容易地做到这一点。

在这里在线尝试


我该如何改变n

@Lembik Pyth程序请求用户输入,该输入在第二个文本框中指定(如果使用在线编译器)。
Jakube 2015年

@Jakube哦,谢谢!它实际上似乎也可以工作:)

6

CJam,58 57 54 51 46字节

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

要运行它,请在WX]和之间插入所需的整数m*

感谢@ jimmy23013的点魔术和高尔夫5个字节!

CJam解释器中在线尝试。

理念

这些答案的大部分内容都很简单,但是使用了两个巧妙的技巧:

  • 代替配对的所有向量的{-1,1} Ñ用的所有向量{-1,0,1} Ñ与期望的概率,则认为计数矢量的三联体的数目在{-1,1} Ñ满足一定条件

    如果我们将三元组的最后两个向量相加,则结果将是{-2,0,2} n的向量。

    由于(-1)+ 1 = 0 = 1 +(-1),所以0 s的出现频率是-2 s和2 s的两倍。

    将每个分量除以2将得到具有所需概率的向量{-1,0,1} n

    由于我们只对标量积是否为0感兴趣,因此可以跳过除以2的运算。

  • 计算满足问题条件的所有三元组和三元组的总数后,我们必须减少结果分数。

    由于分母将始终为2的幂,因此无需计算两个数的GCD,因此只需将两个数除以将分子除以2的最高幂即可。

    为了获得将x除以2的最高幂,我们可以对x〜x + 1进行按位与。

    〜X反转的所有位X,因此,所有尾随0小号成为1秒。通过加入1〜X,那些1旨意变回0秒和最后1〜X + 1将在最后一个匹配1X

    所有其他位要么都是0,要么是不同的,所以按位与运算返回整数,该整数包括x的最后1其后的所有0。这是2除以x的最高幂。

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.

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

@ jimmy23013:这是一些令人印象深刻的魔术。谢谢!
丹尼斯
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.