约瑟夫问题(Josephus Problem)3:谁最后一个出列

版权所有。所有权利保留。

欢迎转载,转载时请注明出处:

http://blog.csdn.net/xiaofei_it/article/details/16813349

本文是论述约瑟夫问题的第三部分,约瑟夫问题的描述在第一部分。请先阅读第一部分。

现在要求输出最后一个出列的人的编号。

第一次见到这个问题是在我高一的时候,那时候搞NOIP,培训的时候碰到了这个题目,当时没想到好的方法,就采用模拟法了。这么多年过去了,前一阵的一个晚上,又想到了这个题目,后来就躺床上想了想,于是就想到了一个比较好的解法。(这也就是我现在写这个系列的文章的原因。)

我在网上搜了一下,发现这个解法和网上的类似。但我还是用自己的语言叙述一下吧。

起初N个人,编号1到N。当数到C(为简单起见,这里假定C<N)的那个人出列后,剩下的人就是

C+1、C+2、…、N、1、2、…、C-1

这时开始数数,编号C+1的人报1,这就成了一个新问题。可以把这个看成一个新队列,即N-1个人,编号为1、2、…、N-1。C+1的新编号为1,C+2的新编号为2,…,C-1的新编号为N-1。

这样我们只要算出N-1规模的队列谁最后一个出列,然后转换到N规模即可。

如果规模为i-1的队列最后一个出列的人编号为p,此人在规模为i的队列中编号为q。

那么q=(p+c) mod i。当然这个要稍微改进一下(请读者自己想想为什么?),改为q=((p+c-1) mod i)+1。

这样我们就可以从i=1的情况递推到i=n的情况了。

假设对于规模为i的队列,最后出列的人编号为pos[i]。

首先i=1时,最后出列的人编号为1,即pos[1]=1。

i>1时,pos[i]=(pos[i-1]+c-1)%i+1。

最后,问题的结果为pos[n]。

当然递推的时候用一个变量pos即可。

程序如下:

#include <iostream>
using namespace std;
int main()
{
	int n,c;
	cout<<"Input n:"<<endl;
	cin>>n;
	cout<<"Input c:"<<endl;
	cin>>c;
	int pos=1;
	for (int i=2;i<=n;i++)
		pos=(pos+c-1)%i+1;
	cout<<pos<<endl;
	return 0;
}


你可能感兴趣的:(算法,约瑟夫,约瑟夫问题,递推,经典问题)