桌面上有 2n 個顏色不完全相同的球,球上的顏色共有 k 種。給你一個大小爲 k 的整數數組 balls ,其中 balls[i] 是顏色爲 i 的球的數量。
所有的球都已經 隨機打亂順序 ,前 n 個球放入第一個盒子,後 n 個球放入另一個盒子(請認真閱讀示例 2 的解釋部分)。
注意:這兩個盒子是不同的。例如,兩個球顏色分別爲 a 和 b,盒子分別爲 [] 和 (),那麼 [a] (b) 和 [b] (a) 這兩種分配方式是不同的(請認真閱讀示例 1 的解釋部分)。
請計算「兩個盒子中球的顏色數相同」的情況的概率。
示例 1:
輸入:balls = [1,1]
輸出:1.00000
解釋:球平均分配的方式只有兩種:
- 顏色爲 1 的球放入第一個盒子,顏色爲 2 的球放入第二個盒子
- 顏色爲 2 的球放入第一個盒子,顏色爲 1 的球放入第二個盒子
這兩種分配,兩個盒子中球的顏色數都相同。所以概率爲 2/2 = 1 。
示例 2:
輸入:balls = [2,1,1]
輸出:0.66667
解釋:球的列表爲 [1, 1, 2, 3]
隨機打亂,得到 12 種等概率的不同打亂方案,每種方案概率爲 1/12 :
[1,1 / 2,3], [1,1 / 3,2], [1,2 / 1,3], [1,2 / 3,1], [1,3 / 1,2], [1,3 / 2,1], [2,1 / 1,3], [2,1 / 3,1], [2,3 / 1,1], [3,1 / 1,2], [3,1 / 2,1], [3,2 / 1,1]
然後,我們將前兩個球放入第一個盒子,後兩個球放入第二個盒子。
這 12 種可能的隨機打亂方式中的 8 種滿足「兩個盒子中球的顏色數相同」。
概率 = 8/12 = 0.66667
示例 3:
輸入:balls = [1,2,1,2]
輸出:0.60000
解釋:球的列表爲 [1, 2, 2, 3, 4, 4]。要想顯示所有 180 種隨機打亂方案是很難的,但只檢查「兩個盒子中球的顏色數相同」的 108 種情況是比較容易的。
概率 = 108 / 180 = 0.6 。
示例 4:
輸入:balls = [3,2,1]
輸出:0.30000
解釋:球的列表爲 [1, 1, 1, 2, 2, 3]。要想顯示所有 60 種隨機打亂方案是很難的,但只檢查「兩個盒子中球的顏色數相同」的 18 種情況是比較容易的。
概率 = 18 / 60 = 0.3 。
示例 5:
輸入:balls = [6,6,6,6,6,6]
輸出:0.90327
提示:
1 <= balls.length <= 8
1 <= balls[i] <= 6
sum(balls) 是偶數
答案與真實值誤差在 10^-5 以內,則被視爲正確答案
思路:
k種顏色的球,從k-1到0依次放球,balls數組存了每種顏色的球的數目。
當放第i個球的時候(i從0到k-1),枚舉在左邊放球的數量j(j從)
左邊還有nl個空位,右邊還有nr個空位,那麼一共有c[nl+nr][balls[k]]這麼多種情況,其中c數組是組合數,
這些情況中,左邊放j個,右邊放balls[k]-j個的情況數是c[nl][j] * c[nr][balls[k]-j]
所以,這麼放的概率是c[nl][j] * c[nr][balls[k]-j] / c[nl+nr][balls[k]]
依次枚舉每種顏色的球在左邊放的數目,每一種顏色的球的放置都是獨立的,不斷更新兩邊的色差,最後色差爲0的那些情況的概率加起來,就是最後答案。
代碼:
double eps=0.00000001;
class Solution {
public:
double c[51][51];
double ans[25][25][9][20];
vector<int>b;
double getc(int n,int i)
{
if(n<=0||i<=0)return c[n][i]=1;
if(c[n][i]>eps)return c[n][i];
return c[n][i]=getc(n-1,i-1)*n/i;
}
double dp(int nl,int nr,int k,int dif)
{
if(k<0)return (dif==10)?1:0;
if(ans[nl][nr][k][dif]>eps)return ans[nl][nr][k][dif];
int nk=b[k];
double res=0;
for(int i=0;i<=nk;i++)
{
if(nl<i || nr<nk-i)continue;
double p=c[nl][i]*c[nr][nk-i]/c[nl+nr][nk];
int tmpdif=(i?1:0)-((i==nk)?0:1);
res+=p*dp(nl-i,nr-nk+i,k-1,dif-tmpdif);
}
return ans[nl][nr][k][dif]=res;
}
double getProbability(vector<int>& balls) {
b=balls;
for(int i=0;i<50;i++)for(int j=0;j<50;j++)getc(i,j);
int n=0;
for(int i=0;i<b.size();i++)n+=b[i];
return dp(n/2,n/2,b.size()-1,10);
}
};