今天面试被问到一个问题:有红白两色球各50个,按照一定分配方法放入两个框子中,另一个人随机从某个框子抓取一个球,问怎样分配可以令第一次抓取到红球的概率最大?
我一开始想当然地回答如此如此这般这般,抓到红球的概率是0.5,……可能由于面试有些紧张,这样的答案有一个非常明显的bug,当时没有意识到,等到面试一结束突然想起来——第一次抓到红球和白球的概率和是1,如果抓到红球最大概率是0.5,翻译过来就是抓到白球的最小概率是0.5,而红球白球没有本质的区别,两者的概率问题应该能够互换。除非不论怎么分配,抓到某种球的概率永远都是0.5,否则我之前的答案就很有矛盾,而我们知道这样的情形是不可能的。
总之,我的回答是大错特错的!!
所以正确答案应该是什么呢?我在平静下来之后继续思考——
首先,框子一共有两个,那么选择拿球的框子时,每种概率都是0.5。
假设从第一个框子中拿到红球的概率是p1,从第二个框子中拿到红球的概率是p2,那么最终抓取到红球的概率是p=0.5*(p1+p2)。
此时,如果一个框子中(假设是第一个框子)只用红球,而另一个框子中有红球和白球,那么p1=1,0<p2<1,于是p=0.5 + 0.5*p2。这样的结果绝对大于0.5。
再次证明我之前的回答没动脑子。
剩下的就好想了。为了使p2尽可能地大,那么第二个框子中的红球要尽可能的多,很容易得出第一个框子放一个红球,第二个框子放49个红球和50个白球这样的结论,此时第一次抓取到红球的概率最大,约为0.75。
稍稍扩展一下,如果小球的数量不是50个呢?那么球的数量越多,最后越接近于0.75,因为这样的p2越接近1。
为了进行验证,我写了如下代码(其中小球数量的初始值可自定):
/************************************/
/** File's name: **/
/** cal.c **/
/** Usage: **/
/** cal.exe NUMBER_OF_RED_BALL **/
/** Written by Si*4 **/
/************************************/
#include
#include
#include
double** MallocBall(int num)
{
int sz = sizeof(double)*num;
int psz = sizeof(double*)*num;
double **ball = NULL;
ball = (double**)malloc(psz);
int i,j;
for(i = 0; i < num; i++)
{
ball[i] = (double*)malloc(sz);
for(j = 0; j < num; j++)
{
ball[i][j]=0.0f;
}
}
return ball;
}
int FreeBall(double **ball, int num)
{
int i;
for(i = 0; i < num; i++)
if(ball[i] != NULL) free(ball[i]);
free(ball);
ball = NULL;
return num;
}
// the number of ball in one basket
double Cal(int this, int that, int num)
{
double p1, p2;
p1 = (this + that == 0)?0:(double)this/(this+that);
p2 = (this + that == num*2)?0:(double)(num - this)/(num*2 - this - that);
p1 = (p1 + p2)/2;
return p1;
}
void Output(double **ball, int num)
{
FILE *pf = fopen("output.txt", "wt");// 打开文件
if(pf == NULL)
{
printf("Open file output.txt failed.\n");
return;
}
printf("r/w"); // 打印第一行标签
fprintf(pf, "r/w");
int r, w;
for(w = 0; w <= num; w++)
{
printf("%5d", w);
fprintf(pf, "%5d", w);
}
printf("\n");
fprintf(pf, "\n");
for(r = 0; r <= num; r++) // 打印结果矩阵(精确到小数点后2位)
{
printf("%3d");
fprintf(pf, "%3d");
for(w = 0; w <= num; w++)
{
printf(" %.2lf", ball[r][w]);
fprintf(pf, " %.2lf", ball[r][w]);
}
printf("\n");
fprintf(pf, "\n");
}
putchar('\n');
if(pf != NULL) fclose(pf); // 关闭文件
}
int main(int argc, char* argv[])
{
int n;
sscanf(argv[1], "%d", &n);
printf("There are %d red balls and %d white balls.\n", n, n);
double **red = MallocBall(n+1); // 二维数组
int r, w; // r和w分别表示在第一个框子中红、白球的个数
for(r = 0; r <= n; r++) // 验证所有可能性
{
for(w = 0; w <= n; w++)
{
double tmp = Cal(r, w, n); // 计算概率
red[r][w] = tmp;
}
}
Output(red, n); // 输出结果(包括屏幕和文件)
FreeBall(red, n+1); // 释放内存
return 0;
}
当两种小球个数是10,20,30时结果如下: