Jesephus problem ( 小议约瑟夫家的问题 )
2014-04-17 10:14
162 查看
问题描述:编号为1~n共n只猴子坐成一圈想要选大王,大家约定从1开始报数数到n的猴子退出,剩下的猴子继续从1开始报数,直到剩下最后一只猴子时,它就被选为大王。
有一种常规的解决思路:模拟选大王的过程。用一个长度为n数组作为标志数组,将每次退出猴子对应编号上标记为FALSE,继续报数,遇到标记为false的元素跳过继续,直到数组中只剩一个标记为true的数组,其就是大王。时间复杂度O(mn)。
为了感性认识,请大家考虑一种极端情况,如果n为100只,最后只剩下2只标记为true的猴子,我们为了得到大王,本只需在2只猴子间进行报数,谁最先报出m,则淘汰。但是程序的做法却需要将100个猴子扫描m-1次进行m-1计数,直到报出m。是不是很复杂?
为了得到大王,我们得拿出我们数学这把利剑,采用递推方式,只需要时间复杂度为O(n)就能解决问题。下面细细道来
递推方法:递推,顾名思义从猴子少的时候推到猴子多的时候,找其中的规律。因为习惯我们把编号设成0~n-1,对于上面问题求解时,我们再将编号加一就是了。以下取m=3进行说明。
f(i):表示当猴子数量为i时,猴王的编号。例如:f(1)=0,当只有一只猴子时,其编号为0,它肯定就是猴王了。f(2)=1,两只猴子从编号为0开始报数,报数为3的猴子退出,很明显猴王编号为1。下面给出猴子依次变化时,猴王变化情况:
![](https://img-blog.csdn.net/20140417102246984?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvemVuZ3hpYW95YW8=/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/Center)
发现规律了f(i)=(f(i-1)+m)%i.对这就是我们需要的。那么要求猴子总数为n的时候,已知初始值f(1)=0,又有了递推公式,是不是很简单了。
再拓展下,我们能不能得到n只猴子依次出队的序列呢,如果这个知道,那儿我们就可以很容易算出编号为i的猴子是第几次出队的,是吧?
咱们继续找规律吧。f(i)下面对应了一列数,从下往上,表示当猴子总数为i时,依次出队的先后顺序。
![](https://img-blog.csdn.net/20140417102311625?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvemVuZ3hpYW95YW8=/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/Center)
是不是发现了?每个标蓝色的数字其对应的一行数字之间仍然是满足(f(j)+m)%i【采用(j)只是为了与猴王的f(i)避免冲突】,但是我们不知道递归的初始值啊,即:蓝色数字怎么求呢?有以下两个方案:
1)对于f(i)序列中共有0,1··i-1个数,我们如果已经知道除了蓝色数以外的数字,通过搜索排除就能知道蓝色数
2)针对每个f(i)序列和我们能算出,用其减去已递推了的数,就能知道蓝色数了
时间复杂度为O(n*n).
代码已传到CSDN,希望大家多多批评指正。
有一种常规的解决思路:模拟选大王的过程。用一个长度为n数组作为标志数组,将每次退出猴子对应编号上标记为FALSE,继续报数,遇到标记为false的元素跳过继续,直到数组中只剩一个标记为true的数组,其就是大王。时间复杂度O(mn)。
为了感性认识,请大家考虑一种极端情况,如果n为100只,最后只剩下2只标记为true的猴子,我们为了得到大王,本只需在2只猴子间进行报数,谁最先报出m,则淘汰。但是程序的做法却需要将100个猴子扫描m-1次进行m-1计数,直到报出m。是不是很复杂?
为了得到大王,我们得拿出我们数学这把利剑,采用递推方式,只需要时间复杂度为O(n)就能解决问题。下面细细道来
递推方法:递推,顾名思义从猴子少的时候推到猴子多的时候,找其中的规律。因为习惯我们把编号设成0~n-1,对于上面问题求解时,我们再将编号加一就是了。以下取m=3进行说明。
f(i):表示当猴子数量为i时,猴王的编号。例如:f(1)=0,当只有一只猴子时,其编号为0,它肯定就是猴王了。f(2)=1,两只猴子从编号为0开始报数,报数为3的猴子退出,很明显猴王编号为1。下面给出猴子依次变化时,猴王变化情况:
发现规律了f(i)=(f(i-1)+m)%i.对这就是我们需要的。那么要求猴子总数为n的时候,已知初始值f(1)=0,又有了递推公式,是不是很简单了。
再拓展下,我们能不能得到n只猴子依次出队的序列呢,如果这个知道,那儿我们就可以很容易算出编号为i的猴子是第几次出队的,是吧?
咱们继续找规律吧。f(i)下面对应了一列数,从下往上,表示当猴子总数为i时,依次出队的先后顺序。
是不是发现了?每个标蓝色的数字其对应的一行数字之间仍然是满足(f(j)+m)%i【采用(j)只是为了与猴王的f(i)避免冲突】,但是我们不知道递归的初始值啊,即:蓝色数字怎么求呢?有以下两个方案:
1)对于f(i)序列中共有0,1··i-1个数,我们如果已经知道除了蓝色数以外的数字,通过搜索排除就能知道蓝色数
2)针对每个f(i)序列和我们能算出,用其减去已递推了的数,就能知道蓝色数了
时间复杂度为O(n*n).
代码已传到CSDN,希望大家多多批评指正。
相关文章推荐
- Algorithm Gossip: 约瑟夫问题(Jossphus Problem)
- 约瑟夫问题(Josephus Problem)4:第k个出列的人是谁
- 约瑟夫(环)问题(Josephus problem)
- 约瑟夫问题(Josephus Problem)
- 约瑟夫问题(Josephus Problem)的两种快速递归算法
- Algorithm Gossip: 约瑟夫问题(Josephus Problem)
- 约瑟夫问题(Josephus problem)1:出列的序列
- lightoj 1179 - Josephus Problem 约瑟夫问题
- 约瑟夫问题(Josephus Problem) 用双向循环链表实现
- 约瑟夫问题(Josephus problem)的一点思考
- 关于约瑟夫问题(Josephus Problem)
- 约瑟夫问题(Josephus Problem)
- 算法: 约瑟夫问题(Joseph Problem)的分析
- Josephus problem(约瑟夫问题)
- 约瑟夫问题Josephus problem
- 约瑟夫问题 The Josephus Problem 非递归算法求解
- Java-约瑟夫问题(Josephus Problem)
- 约瑟夫问题(Josephus Problem)3:谁最后一个出列
- josephus problem——约瑟夫问题
- C语言单向循环链表解决约瑟夫问题