问最后剩下的那个小孩,在以前500人里是第几个???
很经典的一个约瑟夫问题,我看了几个大神的算法,用了点时间才搞懂一个大神用的递归思想,非递归算法的求解方法,确实厉害。
首先假设这里有10个小孩,我们给他们编号为:
0 1 2 3 4 5 6 7 8 9
那么第一次退出之后剩下的编号为:
0 1 3 4 5 6 7 8 9
接下来的报数是接着从编号3开始的,所以上面的编号排列可以转化为:
3 4 5 6 7 8 9 0 1 (1)
我们给这个新的编号重新排列为:
0 1 2 3 4 5 6 7 8 (2)
这样我们可以发现,(2)式的每一个编号通过转化可以得到对应的(1)式位置上的编号:
((2)+3)%10
换句话理解就是,我们发现,当9个人的时候,最后留下的编号是0,而(0+3)%10=3刚好是10个人的时候最后留下的编号,也就是说,n人中我们只要知道最后留下的编号就可以求出n+1人中最后留下的编号。
那么当n=1的时候,我们就可以求出n=2时最后留下的是(0+3)%2=1,//n=1时最后留下的编号是0,而我们是从1开始计数的,所以最后编号 都要+1
所以代码为:
import java.util.*;
public class Test{
public static void main(String[] args) {
int n = 500, m = 3;
int index = 0;
for (int i = 2; i <= n; i++) {
index = (index + m) % i;
}
System.out.println("最后留下的人在原来的人中是第"+(index + 1)+"个");
}
}
求解结果为436
规定统一式子,当有m个人时,报数报到n时退出,都可以用上述思想求解
2:有17个人(编号从0到16),按编号依次排列成一个圆环(编号16的接着编号为0 的人),从编号为0 的人开始报数,数到3的人退出圆环,如此循环,最后留下的那个人的编号是什么?
0,1,2,3,4,5,6,7,8,,9,10,11,12,13,14,15,16
要求:请用面向对象的思想来处理这个问题并在下面写出具体的代码(可以选择你熟悉的语言,如java/C++/C#等)
这个题用上述方法也可以,但是我看到另一种简便的方法,纯粹用ArrayList中的方法实现:
import java.util.ArrayList;
public class Test
{
public static int test(int len)
{
ArrayList<String> data = new ArrayList<String>();
for(int i = 0; i <= len - 1; i++)
{
data.add(i + "");
}
int search = 0;
for(int i = 0; i < len - 1; i++)
{
search += 2;
search %= data.size();
data.remove(search); //很巧妙的运用了remove方法,方法很容易理解,但是我觉得不容易想到,大家可以参
}
return Integer.parseInt(data.get(0).toString()); //考下思路
}
public static void main(String[] args)
{
int result = test(17);
System.out.println("最后留下的人的编号:" + result);
}
}