程序员的算法趣题Q17:30人31足游戏

目录

1. 问题描述

2. 解法1—作为计数问题的闭式解

3. 解法2—作为计数问题的递推表达式

 4. 代码及测试


1. 问题描述

本题来自《程序员的算法趣题》中的第17题。

男生和女生一起参加“30人31足”比赛。由于女生体力有劣势,所以两个女生排在一起的话整个队伍就会在体力上处于明显不利地位。所以原则上尽量不让女生相邻排列,称没有女生相邻排列的排列方式为“合理”排列。

请问,当总共N个男生和女生一起排成一排时,一共有多少种合理的排列方式?

假设这里男生之间、女生之间不考虑区分(即不考虑男生之间的相对位置的不同,也不考虑女生之间的相对位置的不同)。举个例子,4个人(4人5足)的情况下共有8种排列方式,如下所示(B表示boy,G表示Girl):

BBBB, GBBB, BGBB, BBGB, BBBG, GBGB, BGBG, GBBG

2. 解法1—作为计数问题的闭式解

        这个问题可以当作一个计数问题来考虑,可以直接通过数学推导得到闭式(closed-form)解。

        令男生人数为Nb, 女生认识为Ng,首先它们满足关系:

                 (1)

        由于不允许两个女生相邻排列,因此必然满足(考虑Nb个男生排成一排,包括两端在内一共有Nb+1个位置可以插入女生,即Nb个男生构成的队列中最多可以插入Nb+1个女生以构成“合理”排列):

                  (2)

        结合(1)和(2)可得:

         (3)

        接下来,由于男生人数为Nb,包括两端在内一共有Nb+1个空档可以插入女生。同时又由于不允许女生相邻排列,所以不能有两个女生插入同一个空档。在这个条件下,所能构成的合理的排列数的问题就转变成了:Ng个女生放入Nb+1个位置有多少种安排方法?由于女生之间不区分,所以这是一个组合问题,总共有 ,然后对所有Nf的可能取值进行求和即可得到(将N个人的队伍的合理排列方式数记为 ):

               (4)(Nf为Ng的笔误)

3. 解法2—作为计数问题的递推表达式

        将N个人的队伍的合理排列方式数记为 。 

         考虑从左往右安排队伍,则最右边的人为最后一个安排的人。最后的人(即第N个人)有男生和女生两种可能性,分别讨论如下:

  1. 如果最后一个人为男生,则对前N-1个人的排列方式没有约束条件。即这种情况下的排列方式等于前(N-1)个人的“合理”排列方式,也即是
  2. 如果最后一个人为女生,则倒数第二个人必定为男生,进而同理可得对前N-2个人的排列方式没有约束条件。即这种情况下的排列方式等于前(N-2)个人的“合理”排列方式,也即是

         基于以上讨论可以得到递推关系式,如下所示:

            (5)

        这个递推关系式与斐波那契数列的递推关系式完全相同,但是本问题的解序列 的解序列并不构成标准的斐波那契数列,原因在于初始化条件不同。为了利用(5)式解出 的具体值,我们需要给出序列的最初几个值作为初始化条件。

        N=1:很显然 ,这里我们假定允许单独一个女生参赛(“1人2足”)

        N=2: ,“BB”, “BG”, “GB”

        N=3: ,“BBB”, “MBB”, “BMB”, “BBM” , “MBM”

        因此,本问题的递推关系式表达的解为:






  ………………     (6)

        有兴趣的读者可以自行验证式(4)表示的解和式(6)表示的解式完全等价的。

        以上是从最后一个人倒着往前推,但是从第一个正向地往后推也可以得到相同的递推关系。具体来说就是,假设第一个人为男生,第2个人可以为男生也可以为女生,则其后的排法与N-1的情况相同;假设第一个人为女生,第2个人必然为男生,第3个人可以为男生也可以为女生,则其后的排法与N-2的情况相同。由此可得到与式(6)相同的递推关系。

 4. 代码及测试

        编程计算就是以代码的方式实现式(6)所示的递推关系而已,可以以递归(recursion)的方式外加memoization来实现(代码简洁但是有额外计算代价),另一种方式是以迭代(iteration)的方式计算。递归的方式是从目标值开始从大到小反向回溯的方式进行递推计算,而迭代(iteration)则是前向地从小到大地进行递推计算。

        

        上一篇:Q16:3根绳子折成四边形

        下一篇:Q18: 水果酥饼日

        本系列总目录参见:程序员的算法趣题:详细分析和Python全解

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

笨牛慢耕

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值