求解约瑟夫问题两种方法

1:500个小孩围成一圈,从第一个开始报数:1,2,3,1,2,3,1,2,3,……每次报3的小孩退出

 问最后剩下的那个小孩,在以前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);
    }
}

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值