力扣周賽 5427. 兩個盒子中球的顏色數相同的概率

桌面上有 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);
    }
};

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章