从数学分析的角度解决约瑟夫环

 

    约瑟夫环是个经典的问题,相信会单向链表的人都会解决,但显然复杂度是O(mn),若要高效,则必须在数学分析上做点功夫。

    假设这n个人编号为0~n-1,报数从0报到m-1。令k=m mod n,显然k-1为第一位退出者的编号。剩下的n-1人依次为:k,k+1,k+2,。。n-1,0,1,2,。。。,k-2。

    我们换个角度看,这n-1人组成了一个新的约瑟夫环,开始新一轮的报数,而且新约瑟环中的0号就是原约瑟夫环的k号。那么按照这个数按序我们重新编号:

旧约瑟夫环(人)

k

k+1

k+2

.....

n-1

0

1

2

...

k-2

新约瑟夫环(n-1人)

0

1

。。。

n-k-1

n-k+1

n-k+2

n-k+3

.....

n-1

他们的对应关系已经很明显了,p=(p+k)mod n

既然通过n能够推出n-1,那么n-1一样能推出n-2...2,

推出1.算法已经出来了。f(i)表示i个人报数m最后剩下的人的编号。

则最后结果为f(n),有如下的递推关系

f(1)=0;

f(i)=(f(i-1)+m)mod i;i>1;

源程序为:

#include<iostream>

using namespace std;

void main()

{

  long n,m,i,f=0;

cin>>n>>m;

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

for(f+m)%i;

cout<<"最后人的编号为"<<f+1<<endl;

}

本程序采用迭代,实质是递推思想。

时间复杂度是O(n)相对于模拟算法已有很大的提高。

 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值