PHP 约瑟夫环 报数问题,约瑟夫环问题

约瑟夫环问题是一道经典的数据结构题目

问题描述:n个人(编号0~(n-1)),从0开始报数,报到(m-1)的退出,剩下的人继续从0开始报数。求胜利者的编号。

一般我们采用一个循环队列来模拟约瑟夫环的求解过程,但是如果n比较大的时候,采用模拟的方式求解,需要大量的时间来模拟退出的过程,而且由于需要占用大量的内存空间来模拟队列中的n个人,并不是一个很好的解法。

在大部分情况下,我们仅仅需要知道最后那个人的编号,而不是要来模拟一个这样的过程,在这种情况下,可以考虑是否存在着一种数学公式能够直接求出最后那个人的编号。

我们知道第一个人(编号一定是m%n-1) 出列之后,剩下的n-1个人组成了一个新的约瑟夫环(以编号为k=m%n的人开始):

我们先看第一个人出列后的情况,显而易见,第一个出列的人的编号一定是m%n-1,这个人出列后,剩下的n-1个人组成了一个新的约瑟夫环,这个约瑟夫环的第一个人在最开始的环中的编号是k=m%n(就是第一个出列的人的下一个)

k  k+1  k+2  ... n-2, n-1, 0, 1, 2, ... k-2并且从k开始报0。

事实上,可以把这个环又映射成为一个新的环:

k  --- 0

k+1 --- 1

k+2 --- 2

...  ....

k-2 -- n-1

可以看出,这就是原问题中把n替换成n-1的情况,假设我们已经求出来在这种情况下最后胜利的那个人的编号是x,那个倒推回去的那个人的编号就正好是我们要求的答案,显而易见,这个编号应该是(x+k)%n

那么如何知道n-1个人下面的这个x呢,yes,就是n-2个人情况下得到的x'倒推回去,那么如何知道n-2情况下的x'呢,当然是求n-3个人,这就是一个递归的过程

f(1) = 0(f(1)就是现在还剩下1个人,那么无论m为几,这个人总会出列,因此f(1)=0)

f(n) = (f(n-1)+m)%n

那么我们要求f(n),就从f(1)倒推回去即可

点击(此处)折叠或打开

/**

* 约瑟夫问题

* @param $n 总共的人数

* @param $m 第m个人出列

* f(1)=0;

* f(2)=(f(1)+m)%2

* .....

* f(n)=(f(n-1)+m)%n

*/

function yesefu($n,$m){

$last=0;

for($i=2;$i<=$n;$i++){

$last=($last+$m)%$i;

}

return $last+1;//中国人习惯从一开始编号,所以返回值+1

}

echo yesefu(5,2);

?>这种方法比模拟的方法快多了,我们在碰到问题的时候,可以想一想是否有数学公式来求解

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值