您的位置:首页 > 其它

阿里巴巴笔试题2(转载)

2014-03-07 15:49 49 查看
23、一个骰子,6面,1个面是 1,2个面是2, 3个面是3, 问平均掷多少次能使1、2、3都至少出现一次!

解:(没学过《组合数学》的请略过)

设P(N=n)表示第n次(n>2)抛出后1,2,3都出现的概率,问题要求n的期望E(N=n).掷1的概率p=1/6,掷2的概率q=1/3,掷3的概率r=1/2.







写程序求解




#include <iostream>


[cpp] view
plaincopy

using namespace std;

float f(float x)

{

return (1/(1-x)/(1-x)-1-2*x);

}



int main()

{

float p=1.0/6,q=1.0/3,r=1.0/2,e;

e=r*(f(p+q)-f(p)-f(q))+p*(f(q+r)-f(q)-f(r))+q*(f(p+r)-f(p)-f(r));

cout<<e<<endl;

return 0;

}

在Visual Studio下的运行结果为:7.3

答案7.3

24、一个有趣的抛硬币问题

假设有一个硬币,抛出字(背面)和花(正面)的概率都是0.5,而且每次抛硬币与前次结果无关。现在做一个游戏,连续地抛这个硬币,直到连续出现两次字为止,问平均要抛多少次才能结束游戏?注意,一旦连续抛出两个“字”向上游戏就结束了,不用继续抛。

上面这个题目我第一次见到是在pongba的TopLanguage的一次讨论上,提出问题的人为ShuoChen,当时我给出了一个解法,自认为已经相当简单了,先来考虑一下抛硬币的过程:首先先抛一枚硬币,如果是花,那么需要重头开始;如果是字,那么再抛一枚硬币,新抛的这枚如果也是字,则游戏结束,如果是花,那么又需要重头开始。根据这个过程,设抛硬币的期望次数为T,可以得到关系:

  T = 1 + 0.5T + 0.5( 1 + 0.5 * 0 + 0.5T)

解方程可得到 T = 6。

或者根据公式,需要连续抛出n个字的一般情形,结果相当简洁:Tn = 2^(n+1) -2,其中Tn为首次出现连续的n个字的期望投掷数。

参考链接 http://www.cnblogs.com/atyuwen/archive/2010/09/12/coin.html

25、问题描述:

12个高矮不同的人,排成两排,每排必须是从矮到高排列,而且第二排比对应的第一排的人高,问排列方式有多少种?

这个笔试题,很YD,因为把某个递归关系隐藏得很深。

问题分析:

我们先把这12个人从低到高排列,然后,选择6个人排在第一排,那么剩下的6个肯定是在第二排。

用0表示对应的人在第一排,用1表示对应的人在第二排,那么含有6个0,6个1的序列,就对应一种方案。

比如000000111111就对应着

第一排:0 1 2 3 4 5

第二排:6 7 8 9 10 11

010101010101就对应着

第一排:0 2 4 6 8 10

第二排:1 3 5 7 9 11

问题转换为,这样的满足条件的01序列有多少个。

观察1的出现,我们考虑这一个出现能不能放在第二排,显然,在这个1之前出现的那些0,1对应的人

要么是在这个1左边,要么是在这个1前面。而肯定要有一个0的,在这个1前面,统计在这个1之前的0和1的个数。

也就是要求,0的个数大于1的个数。

OK,问题已经解决.

如果把0看成入栈操作,1看成出栈操作,就是说给定6个元素,合法的入栈出栈序列有多少个。

这就是catalan数,这里只是用于栈,等价地描述还有,二叉树的枚举,多边形分成三角形的个数,圆括弧插入公式中的方法数,其通项是c(2n,n)/(n+1)。

23题解答见
http://blog.csdn.net/quanben/article/details/6918209
话少说了,原题集出处:/article/1422771.html

题目: 一个骰子,6面,1个面是 1, 2个面是2, 3个面是3,问平均掷多少次能使1、2、3都至少出现一次。

方法: 面对面试概率题几乎屡试不爽的分叉树递归列方程法。

这是一个求数学期望的问题,最终是求1,2,3出现至少一次的最短长度的期望。

这样分叉树的每个节点是一个期望状态,而每个分叉是一次投掷结果。将后续期望出现1、2、3各至少一次的情形记作L123(即题目所求),将后续期望出现1、2各至少一次(3无关)情形记作L12,而1至少一次(2,3无关)情形L1,其余数值符号类推,则树结构如下(列出4级结构已经足够):

第一级(树根)第二级第三级第四级别
L123掷1->L23掷1->L23同状态
掷2->L3根据投掷结果,或继续期待L3,或已经达到目标
掷3->L2根据投掷结果,或继续期待L2,或已经达到目标
掷2->L13掷1->L3根据投掷结果,或继续期待L3,或已经达到目标
掷2->L13同状态
掷3->L1根据投掷结果,或继续期待L1,或已经达到目标
掷3->L12掷1->L2根据投掷结果,或继续期待L2,或已经达到目标
掷2->L1根据投掷结果,或继续期待L1,或已经达到目标
掷3->L12同状态
接下来,就是要排出方程,因为一共7个未知数,如果排出7个线性方程就能解决问题。

这方程组里的未知数对应上述的状态,而其数值则是一个对长度(投掷次数)的数学期望。

根据这个树状结构和其中的递归关系,这个方程组就是:

L123 =p1 (L23+1)
+ p2 (L13+1)+
p3 (L12 +1)
= p1 L23 +p2 L13+ p3 L12 +1

(以这个L123为例,解释,投掷1的概率是p1而由此得到的结果是需要期待后续2和3各至少出现一次,于是长度期望是L23+1,加1是因为投掷了一次,亦即即增进一级)

L23 = p1 L23 +p2 L3+ p3 L2 +1

L13 = p1 L3 +p2 L13+ p3 L1 +1

L12 = p1 L2 +p2 L1+ p3 L12 +1

L1 =p1 + p2 L1+ p3 L1 +1

(这里实际上是 L1 =p1 ·1+
p2 (L1+1)+
p3 (L1 +1) =p2 L1+ p3 L1 +1,因为对L1情形,如果投了1就目的达到终止了)

L2 =p2 + p1 L2 + p3 L2 +1

L3 =p3 + p1 L3 +p2 L3+1

(以上一开始没注意,多加了悬空的概率项,故计算有误)

其中 p1,p2 和 p3分别是掷出1,2和3的概率,即1/6,1/3,1/2。

于是求解这个方程,得到:

L1 =6, L2 =3, L3 =2

L12 =7, L13 =13/2, L23 =19/56

L123 = 219/30=
7.3 259/36 ~=7.14

故以上如果没有计算错误,该题结果是,平均掷7.3 约7.14次可出现这些面值各至少一次。

在 <<计算机程序设计艺术>>,第三版,DonaldE.Knuth著,苏运霖译,第一卷,508页,给出了证明:

问题大意是用S表示入栈,X表示出栈,那么合法的序列有多少个(S的个数为n)

显然有c(2n,n)个含S,X各n个的序列,剩下的是计算不允许的序列数(它包含正确个数的S和X,但是违背其它条件).

在任何不允许的序列中,定出使得X的个数超过S的个数的第一个X的位置.然后在导致并包括这个X的部分序列中,以

S代替所有的X并以X代表所有的S.结果是一个有(n+1)个S和(n-1)个X的序列.反过来,对一垢一种类型的每个序列,我们都能

逆转这个过程,而且找出导致它的前一种类型的不允许序列.例如XXSXSSSXXSSS必然来自SSXSXXXXXSSS.这个对应说明,不允许

的序列的个数是c(2n, n-1),因此an = c(2n, n) - c(2n, n-1).[Comptes RendusAcad.Sci.105(Paris, 1887), 436~437]

验证:

其中F表示前排,B表示后排,在枚举出前排的人之后,对应的就是后排的人了,然后再验证是不是满足后面的比前面对应的人高的要求.

C/C++ code

[cpp] viewplaincopy

#include <iostream>

using namespace std;



int bit_cnt(int n)

{

int result = 0;

for (; n; n &= n-1, ++result);

return result;

}



int main()

{

int F[6], B[6];

int ans = 0;

for (int state = 0; state < (1 << 12); ++state) if (bit_cnt(state) == 6)

{

int i = 0, j = 0;

for (int k = 0; k < 12; ++k) if (state&(1<<k)) F[i++] = k; else B[j++] = k;

int ok = 1;

for (int k = 0; k < 6; ++k) if (B[k] < F[k]) {ok = 0; break;}

ans += ok;

}

cout << ans << endl;

return 0;

}

结果:132

而c(12, 6)/7 = 12*11*10*9*8*7/(7*6*5*4*3*2) =132

注意:c(2n, n)/(n+1) = c(2n, n) - c(2n, n-1)

估计出题的人也读过 <<计算机程序艺术>>吧.

PS:

另一个很YD的问题:

有编号为1到n(n可以很大,不妨在这里假定可以达到10亿)的若干个格子,从左到右排列.

在某些格子中有一个棋子,不妨设第xi格有棋子(1 <=i <=k, 1<=k <=n)

每次一个人可以把一个棋子往左移若干步,

但是不能跨越其它棋子,也要保证每个格子至多只有一个棋子.

两个人轮流移动,移动不了的为输,问先手是不是有必胜策略.
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: