N个座位坐满人的期望
公交车上有一排 n 个座位,这一排的 n 个座位有个规定:乘客选中落座的前后位置,不允许坐人。即如果某位置的相邻位置有其他乘客,则该座位不会被选择。1 号座位与 2 号相邻,n 号座位与 n-1 号相邻,除了 1 号与 n 号座位,任意 i 号座位都与 i-1 和 i+1 号座位相邻。乘客源源不断的依次上车,每次上一人,随机选符合规定的座位,求这个n个座位坐满人的期望。
示例分析
n=1 时,共有1种坐满人的坐法,坐满时的总人数为1,期望=$\frac{1}{1}=1$
n=2 时,共有2种坐满人的坐法,坐满时的总人数为2,期望=$\frac{2}{2}=1$
n=3 时,共有3中坐满人的坐法,坐满时的总人数为5,期望=$\frac{5}{3} \approx 1.67$
- 第一种坐法: 第一个乘客选择中间位置坐,后来乘客按规则,无法选中第一和第三个座位,该坐法共有1人落座。
- 第二种坐法:第一个乘客选择第一个位置,第二个乘客则只能选择最后一个位置,该坐法共有2人落座。
- 第三种坐法:第一个乘客选择组后一个位置,第二个乘客则只能选择第一个位置,该坐法共有2人落座。
从示例易得,期望的计算公式, $h_i(n)$分别为 n 个座位时,第 i 个坐法可以落座的人数, N为坐法的数量
\[E(n) = \frac{\sum_{i=1}^{N}h_i(n)}{N}\]因此,问题的关键是求出座位数量为 n 时的所有坐法数量,以及每种坐法对应的落座人数。
子问题
假如已经知道 n 个座位时的所有坐法,出于临时需要,公交车上在最后临时增加了一个座位(第n+1个座位),由于规则的限制:落座的前后无法入座,新增的第n+1个座位能否落座,取决于第n个座位是否有人落座。 因此,第n个位置(最后一个位置)是否有人落座,需要成为标记子问题的一个变量或者状态,子问题的状态值是其因变量。
令:$f_1(n)$ 表示 n个座位时,最后一个座位坐人时的方法数; $f_2(n)$表示n个座位时,最后一个座位不坐人时的方法数。 $h_1(n)$表示 n个座位时,最后一个座位坐人时,可落座的座位数量;$h_2(n)$表示n个座位时,最后一个位置不坐人时,可落座的座位数量。
n=1时:$h_1(1)=1, h_2(1)=0, f_1(1)=1, f_2(1)=0$
n=2时:$h_1(2)=1, h_2(2)=1, f_1(2)=1, f_2(2)=1$
$n_1$ | $n_2$ | |
---|---|---|
i=1 | [1] | [] |
i=2 | [] | [1] |
$n_1$, $n_2$ 表示第一、第二个座位,第一列标记i=1, i=2 表示第一、第二个坐法,[]表示座位不可入座,[1]表示该座位可入座且被第一个人入座, 例如,当i=1时,在该坐法下,第一个座位可以坐人,但因为只有该位置可以坐人,所以该只有一种坐法。
n=3时, 落座方案数和可落座状态
$n_1$ | $n_2$ | $n_3$ | |
---|---|---|---|
i=1 | [] | [1] | [] |
i=2 | [1] | [] | [2] |
i=3 | [2] | [] | [1] |
n=3时,当最后一个位置可以落座时,可落座的状态,只需从n=2时,最后一个位置不可落座时的状态转移过来(将第三个可入座的座位放在第二个不可入座的座位之后),就可满足约束条件。此时,可落座的位置数量为 h_1(3) = $h_2(2) + 1 = 2$。
由于第三个位置可以落座,此时第一个用户可以选择第一个座位和第三个座位入座,有两种选择,第二个用户只有一种选择,可落座的方法数量为 2。 从座位的角度看, 新增座位后有两个座位可入座,所以新增座位也有两种选择:第一个用户入座,第二个用户入座;可落座的座位数量 等价于 新增座位的选择方法数,所以$f_1(3)=f_2(2) \times h_1(3) = 2$。
同理,n=3时,当最后一个位置不可落座时, 由于没有新的位置可以落座,此时可落座的座位数量,就是n=2时的最后一个位置可坐人时的可落座数量: $h_2(3) = h_1(2) = 1$, 入座的方法数量: $f_2(3) = f_1(2)$
n=4时,落座方案数和可落座状态
$n_1$ | $n_2$ | $n_3$ | $n_4$ | |
---|---|---|---|---|
i=1 | [] | [1] | [] | [2] |
i=2 | [1] | [] | [2] | [] |
i=3 | [2] | [] | [1] | [] |
i=4 | [] | [2] | [] | [1] |
n=5时,落座方案数和可落座状态
$n_1$ | $n_2$ | $n_3$ | $n_4$ | $n_5$ | |
---|---|---|---|---|---|
i=1 | [] | [1] | [] | [2] | [] |
i=2 | [1] | [] | [2] | [] | [3] |
i=3 | [2] | [] | [1] | [] | [3] |
i=4 | [] | [2] | [] | [1] | [] |
i=5 | [2] | [] | [3] | [] | [1] |
i=6 | [1] | [] | [3] | [] | [2] |
i=7 | [3] | [] | [1] | [] | [2] |
i=8 | [3] | [] | [2] | [] | [1] |
综上分析,得到状态转移公式:
\[\begin{align*} & h_1(n) = h_2(n-1) + 1 \\ & h_2(n) = h_1(n-1) \\ & f_1(n) = f_2(n-1) * h_1(n) \\ & f_2(n) = f_1(n-1) \\ & E(n) = \frac{f_1(n) \times h_1(n) + f_2(n) \times h_2(n)}{f_1(n) + f_2(n)} \end{align*}\]代码
double solve(int n) {
vector<int> h1(n+1), h2(n+1); // 最后一个位置坐人/不坐人的可坐座位数量
vector<int> f1(n+1), f2(n+1); // 最后一个位置坐人/不坐人的方法数
if(n<1) return -1; // invalid
h1[1] = 1; h2[1] = 0;
f1[1] = 1; f2[1] = 0;
h1[2] = 1; h2[2] = 1;
f1[2] = 1; f2[2] = 1;
if (n==1 || n==2) {
return (h1[n] * f1[n] + h2[n]*f2[n])*1. / (f1[n] + f2[n]);
}
for(int i=3; i<=n; ++i) {
h1[i] = h2[i-1] + 1; h2[i] = h1[i-1];
f1[i] = f2[i-1] * h1[i]; f2[i] = f1[i-1];
}
return (f1[n] * h1[n] + f2[n] * h2[n]) * 1. / (f1[n]+f2[n]);
}
// 状态压缩
double solve(int n) {
int h1, h2; // 最后一个位置坐人/不坐人的可坐座位数量
int f1, f2; // 最后一个位置坐人/不坐人的方法数
if(n<1) return -1; // invalid
// n=1时
if (n== 1) {
h1 = 1; h2 = 0;
f1 = 1; f2 = 0;
}
if (n==2) {
h1 = 1; h2 = 1;
f1 = 1; f2 = 1;
}
if (n==1 || n==2) {
return (h1 * f1 + h2 * f2)*1. / (f1 + f2);
}
for(int i=3; i<=n; ++i) {
int old_h1 = h1;
h1 = h2 + 1; h2 = old_h1;
int old_f1 = f1;
f1= f2 * h1; f2 = old_f1;
}
return (f1 * h1 + f2 * h2) * 1. / (f1+f2);
}
其他解法
地铁上一排n个座位坐满人的期望 (最后f(n)的递推公式少了系数2)
令:$f(n)$为座位数量为n时候的期望, n个座位时,第一个人上车,有n种类选择:
选择第一个位置时,期望=$\frac{1}{n}(1 + f(n-2))$
选择第二个位置时,期望=$\frac{1}{n}(1 + f(n-3))$
选择第三个位置时,期望=$\frac{1}{n}(1 + f(n-4) + f(1))$
选择第四个位置时,期望=$\frac{1}{n}(1 + f(n-5) + f(2))$
…
选择第n-2个位置时,期望=$\frac{1}{n}(1+f(1)+f(n-4))$
选择第n-1个位置时,期望=$\frac{1}{n}(1+f(2)+f(n-5))$
选择第n个位置时,期望=$\frac{1}{n}(1+f(n-2))$
将选择所有位置的期望相加: $f(n) = \frac{2}{n}(f(1) + f(2) + … + f(n-2)) + 1$
double solve(int n) {
vector<double> f(n+1);
f[0]=0,f[1]=1,f[2]=1;
for(int i=3;i<=n;i++) {
double sum = 0;
for(int k=1; k<=i-2; ++k){
sum += f[k];
}
f[i] = ((2. / i ) * sum) + 1.;
}
return f[n];
}
两种解法结果不一致原因分析
比较两种解法在n取不同值的时候的结果
第一种 | 第二种 | |
---|---|---|
n=3 | 1.667 | 1.667 |
n=4 | 2 | 2 |
n=5 | 2.75 | 2.467 |
n=6 | 3 | 2.88889 |
n=7 | 3.8 | 3.32381 |
n=8 | 4 | 3.75556 |
n=9 | 4.8333 | 4.18801 |
为什么两种解法不一致??
在第一种解法中,第 n 个座位时的入座方法数状态只考虑从第 n-1 座位时的入座方法数状态转移过来,无形中添加了顺序的限制,这样其实限制了乘客选择座位的顺序。例如当n=5时,第一个乘客选择了座位1,第二个乘客按照顺序选择,则只能选择座位3,而不能选择座位4、座位5。 针对这个问题,选择在有$x$个座位可入座时,引入全排列$x!$,即:$f_1(n)=f_2(n-1) \times h_1(n), f_2(n) = f_1(n-1)$,顺序的问题算是解决了。
在第一种解法中,只考虑了相邻入座乘客间隔1个空座的情况,这相当于求解n个座位最多可入乘客的期望。 题目中没有这样限制条件,因此,第一种解法中少考虑了相邻入座乘客间隔2个空座 以及 同时存在间隔1个空座、2个空座的情况。
只考虑相邻入座乘客间隔1个空座时,最后一个位置是否入座可以将可入座座位数量分成两类,每一类中可入座数量相同。当考虑间隔两个空座时,$h_1(n), h_2(n)$ 则不够用了,$x$个间隔2个空座的情况 X $y$ 个间隔1个空座的情况,组合数量太多,分析过于繁琐。
比如,在满足前后无人的要求下,第 n 个状态也能从第n-3个状态转移出来。例如,当n=5时,当第五个座位可以坐人时,从n=2时的状态转移过来,此时,n=2状态下的最后一个可入座座位 和第5个座位之间的座位是否可入座,依赖第五个座位和n=2时最后一个可入座座位的位置序号,当选择他们中间的某个合法位置落座时,可落座的区间变成了两个,这样的分析起来非常复杂。
后记
该题目来自与中国某互联网金融大厂面试题,面试时没有AC出,遂记下,徐图之。