想出了解决这个问题的方法,最后开始用Java编写它。这给出了一个精确的解决方案,用于计算在给定船只和射击的情况下m
船只未被击中的概率。然而,它在计算上是相当昂贵的。首先,总结一下我所做的事情:k
n
概率等于射击完全m
未命中的船只的方式总数除以射击船只的方式总数。
P = m_misses / total
总计是k^n
,因为每次射击都可以击中一k
艘船。
要获得分子,请从 开始nCr(k,m)
。这是选择m
不被击中的船只的方式的数量。这乘以k-m
没有错过任何击中船只的方式的数量就是总概率。
nCr(k,m)*(k-m_noMiss)
P = ---------------------
k^n
现在计算分子中的第二项。这是所有镜头分布的总和,即某个镜头分布发生的方式有多少。例如,如果 2 艘船被 3 颗子弹击中,并且每艘船至少被击中一次,则可以通过以下方式击中它们:
100
010
001
110
101
011
炮弹分布等于 k 的长度 km 组成。在这种情况下,我们将有 [2,1] 和 [1,2],长度为 2 的 3 组合。
对于第一个构图,[2,1],我们可以通过从 3 次射击中选择 2 次击中第一艘船,然后从剩余 1 次中选择 1 次击中第二艘来计算生成它的方式的数量,即nCr(3,2) * nCr(1,1)
. 请注意,我们可以将其简化为3!/(2!*1!)
. 该模式适用于所有镜头模式,因此某个模式 ,p
可以出现的方式数可以写为n!/prodSum(j=1,k-m,p_j!)
,其中符号表示从 1 到 的乘积和k-m
,j
是一个索引,p_j
表示 中的j
第 项p
。
如果我们定义P
为 的所有长度k-m
组合的集合,则船舶未被击中n
的概率为:m
nCr(k,m)*sum(p is an element of P, n!/prodSum(j=1,k-m,p_j!))
P = --------------------------------------------------------------
k^n
符号有点草率,因为没有办法将数学符号方程放入 SO,但这就是它的要点。
话虽如此,这种方法效率极低,但我似乎找不到更好的方法。如果有人可以简化这一点,请务必发布您的方法!我很好奇它是如何做到的。
以及用于执行此操作的 java 代码:
import java.util.ArrayList;
import java.util.Arrays;
import org.apache.commons.math3.util.ArithmeticUtils;
class Prob{
public boolean listsEqual(Integer[] integers, Integer[] rootComp){
if(integers.length != rootComp.length){
return false;
}
for (int i = 0; i < integers.length; i++){
if(integers[i] != rootComp[i]){return false;};
}
return true;
}
public Integer[] firstComp(int base, int length){
Integer[] comp = new Integer[length];
Arrays.fill(comp, 1);
comp[0] = base - length + 1;
return comp;
}
public Integer[][] enumerateComps(int base, int length){
//Provides all compositions of base of size length
if(length > base){return null;};
Integer[] rootComp = firstComp(base, length);
ArrayList<Integer[]> compsArray = new ArrayList<Integer[]>();
do {
compsArray.add(rootComp);
rootComp = makeNextComp(rootComp);
} while(!listsEqual(compsArray.get(compsArray.size() - 1), rootComp));
Integer[][] newArray = new Integer[compsArray.size()][length];
int i = 0;
for (Integer[] comp : compsArray){
newArray[i] = comp;
i++;
}
return newArray;
}
public double getProb(int k, int n, int m){
//k = # of bins
//n = number of objects
//m = number of empty bins
//First generate list of length k-m compositions of n
if((n < (k-m)) || (m >= k)){
return 0;
}
int[] comp = new int[n-1];
Arrays.fill(comp, 1);
comp[0] = n - (k-m) + 1;
//Comp is now the first
Integer[][] L = enumerateComps(n, k-m);
double num = 0;
double den = Math.pow(k, n);
double prodSum;
int remainder;
for(Integer[] thisComp : L){
remainder = n;
prodSum = 1;
for(Integer thisVal : thisComp){
prodSum = prodSum * ArithmeticUtils.binomialCoefficient(remainder, thisVal);
remainder -= thisVal;
}
num += prodSum;
}
return num * ArithmeticUtils.binomialCoefficient(k, m) / den;
}
public Integer[] makeNextComp(Integer[] rootComp){
Integer[] comp = rootComp.clone();
int i = comp.length - 1;
int lastVal = comp[i];
i--;
for(; i >=0 ; i--){
if (comp[i] != 1){
//Subtract 1 from comp[i]
comp[i] -= 1;
i++;
comp[i] = lastVal + 1;
i++;
for(;i < comp.length; i++){
comp[i] = 1;
};
return comp;
}
}
return comp;
}
}
public class numbersTest {
public static void main(String[] args){
//System.out.println(ArithmeticUtils.binomialCoefficient(100,50));
Prob getProbs = new Prob();
Integer k = 10; //ships
Integer n = 10; //shots
Integer m = 4; //unscathed
double myProb = getProbs.getProb(k,n,m);
System.out.printf("Probability of %s ships, %s hits, and %s unscathed: %s",k,n,m,myProb);
}
}