时间:2014.05.26
地点:基地一楼
心情:额呀~
------------------------------------------------------------------------------
一、约瑟夫环问题
约瑟夫环问题的具体描述是:设有编号为1,2,……,n的n(n>0)个人围成一个圈,从第1个人开始报数,报到m时停止报数,报m的人出圈,再从他的下一个人起重新报数,报到m时停止报数,报m的出圈,……,如此下去,直到所有人全部出圈为止。
------------------------------------------------------------------------------
二、分析
1. 现假设编号从0开始到n-1,那么按m报数,可知第一次出圈的人编号为 m%n-1
2. 剩下人有构成一个新约瑟夫环,人数少一,设k=m%n,那么这个新约瑟夫环为 k,k+1,k+2,k+3,......n-1,0,1,2,......k-2
3.我们将这个新约瑟夫环重新编号为:0 1 2 3 n-1
即会形成这样一种映射关系: k——0 k+1——1 k+2——2
n-1——n-1-k 0——n-k 1——n-k+1 2——n-k+2
k-2——n-2
4.先来讨论一个小问题:已知后面下标如推导前面下标,显然我们将后面下标加上k可得 k,k+1,k+2,......n,n+1,n+2,......n+k-2
前面一部分是得到之前正确的下标了,但后面部分显然还要模n才可,由此可得由变化后的下标ib推导变化前的下标if公式为:
if=(ib+k)%n
5.现在在一个约瑟夫环中,我们倒着看这个问题,执行时还是按正常的顺序执行,每一轮出圈的人它在上一轮中的编号现在很容易算出,同样,通过这样层层淘汰,最后没出圈的那个人即胜利着,它在最后一轮淘汰中得以生存,我们也可以迅速知道它在倒数第二轮中的编号,二由倒数第二轮中的编号我们也还可以得出它在倒数第三轮中的编号,如此一直可递归到原始编号,即为所解,显然这是一个时间复杂度为O(n)的问题。
------------------------------------------------------------------------------
#include<iostream>
using namespace std;
int Josephus(size_t n, size_t m)
{
if (n == 1)
return 0;
else
return (Josephus(n - 1,m) +m%n) % (n);
}
int main()
{
cout << Josephus(41,3) << endl;
}