这是一道概率题,假设输入balls表示所有的球数目。要讲球等分成两部分,a and b。要求sum(a)==sum(b) and sumtype(a)==sumtype(b),总共有多少种分割方式。
首先,总共的分割方式为perms(balls),比如balls = [1,2,3],1号颜色球有1个,2号颜色有2个,3号颜色有三个球。那么总共的扰动方式为6个位置中选1个,剩下5个位置中选2个,剩下3个位置放3个,总共是factor(sum(balls))/factor(ball[0])*factor(ball[1])*factor(ball[2])
那么所有这些方式中,有多少种成功的扰动呢?采用dfs遍历所有的a b包含的k个类别的样本数【很强的思路】,如果符合要求,那么包含的成功样本数为perm(a)*perm(b)。
class Solution {
public:
vector<double> gainfactorialDp(int nums){
vector<double> res;
res.push_back(1);
for(int i=1;i<=nums;i++){
res.push_back(res[i-1]*i);
}
return res;
}
// count how many perms for a (ball nums)
double perm(vector<int>& a, vector<double>& factors, int allballs){
double res = factors[allballs];
for(int i=0;i<a.size();i++){
res /= factors[a[i]];
}
return res;
}
// find all cases for balls: [1,2,3]
// [0,0,0], [0,0,1], [0,0,2], [0,0,3]
// [0,1,0], [0,1,1], [0,1,2], [0,1,3]
// [0,2,0], [0,2,1], [0,2,2], [0,2,3]
double successperm = 0;
void dfs(vector<int>& balls, vector<int>& a, vector<int>& b, int pos, vector<double>& factors){
// a[pos], b[pos] set values from [0, balls[pos]]
if (pos==balls.size()){
// whether successful?? sum(a)==sum(b) sum(atype)==sum(btype)
int suma = 0;
int sumb = 0;
int sumtypea = 0;
int sumtypeb = 0;
for(int i=0;i<a.size();i++){
suma += a[i];
sumb += b[i];
if (a[i]>0){sumtypea++;}
if (b[i]>0){sumtypeb++;}
}
if (suma==sumb&&sumtypea==sumtypeb){
successperm += perm(a, factors, suma)* perm(b, factors, sumb);
}
}
else{
for(int i=0;i<=balls[pos];i++){
a[pos] = i;
b[pos] = balls[pos]-i;
dfs(balls, a, b, pos+1, factors);
}
}
}
double getProbability(vector<int>& balls) {
int allballs = 0;
for(int i=0;i<balls.size();i++){allballs += balls[i];}
vector<double> factors = gainfactorialDp(allballs);
//for(int i=0;i<factors.size();i++){cout<<factors[i]<<endl;}
double totalperms = perm(balls, factors, allballs);
// count successful perms
vector<int> a(balls.size(), 0);
vector<int> b(balls.size(), 0);
dfs(balls, a, b, 0, factors);
//cout<<totalperms<<" "<<successperm<<endl;
return successperm/totalperms;
}
};