约瑟夫斯问题

约瑟夫斯问题:

有n个人围成一圈,报数从1到m依次循环报数,报到m的就退出(死)。

现在我们来看递推,由于为了方便表示(s+m)%i=0的情况,我们让第一人的编号为0,(从一开始也可以)。

既然你问递推,那步骤就不说了,只说这个公式吧

让获胜者的编号为0(最后一个人只有他了当然是0)f(i)表示获胜者在剩下i个人时的那一局的编号

则f(1)=0

f(i)=[f(i-1)+m]%i.

这里我们可以这样理解

如果获胜者在这一局游戏中编号为k(从0开始编号),而每一局中会大声喊出他的编号的人是m个(注意喊得数字从0开始,则喊m-1的人死,但这个人是第m个人),而第m个人又是获胜者的前面第k+1个人,那么如果上一轮的游戏的人数足够(叫了m次还没有人重复叫),则获胜者在上一局的编号是[(m-1)+(k+1)]=m+k(m-1代表死的那个人的编号,而k+1代表死的那个人的后面第n个人的编号),即在上一局中他是第m+k+1个人。

但是,为什么要%i,因为如果在上一局中,人数不够m-1个,那么是不是就会有的人重复报了两次甚至更多次数!!!!那么,就可以看成数学上的一个周期问题,那么%i,假设为倒数第二句,i=2

那么,i是不是就起了一个限定编号的作用呢,即可以得到的编号只有0和1(余数只有这两个),那么,又知道m+k为有足够人时的时候获胜者的编号,则(k+m)%i不就是把他的编号变成以0~i-1的周期轮换运动吗,即设k+m=3;i=2。 把 0 1 2 3  中的不能得到的2 3变成  0 1 则为 0101来表示吗

那么是不是就是获胜者在这一局当中的编号呢!

那么获胜者不就是第s+1个人吗!

源代码:

#include<iostream>
using namespace std;

void Joseph(int n,int m)
{
	int i,s=0;
	for(i=2;i<=n;i++)
	
	 s=(s+m)%i;   //s表示的是上一轮的结果,m代表是每多少个人出列一次,i代表当前已经出列了多少个人。
 	 
    return (s+1); 
}
int main()
{
    int m,n;
    cin>>n>>m;
    cout<<Joseph(n,m)<<endl;
    //Joseph(n,m);
	return 0;
}



猜你喜欢

转载自blog.csdn.net/qq_36666756/article/details/79855164
今日推荐