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

来源:互联网 发布:深圳数控车床编程招聘 编辑:程序博客网 时间:2024/05/01 22:06

 

    约瑟夫环是个经典的问题,相信会单向链表的人都会解决,但显然复杂度是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)相对于模拟算法已有很大的提高。