从华为在重邮的一道机试题开始:
典型的一道约瑟夫问题;
网上讲的求解过程是这样的:
(参考链接: 1:百度百科 约瑟夫问题http://baike.baidu.com/view/213217.htm?fr=aladdin
2: http://www.cnblogs.com/EricYang/archive/2009/09/04/1560478.html
在n个人时 编号 0 1 2 ... n-1,从0 数到 m-1,数到m-1的人出列,则本次出列的人编号为 (m-1)%n,
则下次从 m%n开始重新计数,剩下的n-1个人构成环 m%n (m+1)%n ... (n-1) 0 1 ...(m-2)%n,
由于它们从1重新开始计数,则有它们新的序号为 0 1 ... n-2,
设在 旧的环(长度为 n)那个人中的编号为 x'',在新的环(长度为n-1)该人的编号为 x,则由x推得x"的递推式为 x" = (x+m)%n,
即如果我们知道 n-1个人时最终留下的人编号为 f[n-1],则 该人在n个人的环中编号为 f[n] = (f[n-1] + m)%n.又已知n=1时 f[1] = 0,由此可以反向求得 f[n];
写成代码形式为:
int x=0;
for(int i=2;i<=n;i++){ //i代表当前活着的人数
x = (x + m)%i;
}
注意最终输出时如果起始编号为1,即n个人编号为 1 2...n时,需要令上面计算出的 x +=1;
个人觉得上述理解方式不是很容易理解,以下给出个人的一种较容易接受的求解理解方式。
已知 只有1个人即n =1,时 留下的人编号显然为 0,
那么2个人时即 n =2,时对应确定的m,留下的人是不是确定唯一的呢。假设m =10,可以自己数一下,一定是编号为1的人第一个出列,剩下编号为0的人。
递推关系:对应n个人,找到第一个出列的人,显然为 (m-1)%n;则转换为问题规模为n-1时,起始人旧编号为 m%n,新编号为0,如果已知n-1人时问题解为x(指从0开始的编号为x),则其在n个人的问题中旧编号为 x'' = (m+x)%n;
上图如下:
根据其n 由小到大的递推过程可以有如下表达式:
f[n] = ( (m-1)%n + 1 + f[n-1] ) % n,
即 f[n] = (f[n-1] + m) % n;
由此递推式可以写出同上代码。