约瑟夫环问题——递归解决

问题:

约瑟夫,是一个古犹太人,曾经在一次罗马叛乱中担任将军,后来战败,他和朋友及另外39个人躲在一口井里,但还是被发现了。罗马人表示只要投降就不死,约瑟夫想投降,可是其他人坚决不同意。怎么办呢,他想到一个主意:
让41个人围成一个圆圈,从第一个人开始报数,数到3的那个人被旁边的人杀死。这样就可以避免自杀了,因为犹太人的信仰是禁止自杀的。结果一群人杀来杀去最后只剩下两个了,就是约瑟夫和他朋友,于是两人愉快地去投降了。

请问:约瑟夫和朋友站在什么位置才保住了性命?(即原始位置应该在哪?)

【举例】
(1)假设5个人,数到3杀一个
0 1 2 3 4
A B C1 D E ——初始位置,C第一个被杀
D E A2 B——重新排位,A第二个被杀
B D E3——E第三个被杀
B4 D——B第四个被杀
D——D活了下来,初始位置为3
(2)假设4个人
0 1 2 3
A B C1 D
D A B2
D2 A
A

对于5个人:下一次new跟上一次old报数时,同一个人的下标规律为:old = (new+3)%5

即:old = (new+m)%n ——n为人数,m为间隔数
令:f(n,m)=old 则f(n-1,m)=new
有:f(n,m) = (f(n-1,m)+m)%n

故而可用递归解决

//输入数:0~n-1  输出:最后一个被杀的人的原始下标
//n:人数  m:报数记录
//每次报数从0开始,下角标为old=(new+3)%n
import java.util.Scanner;
public class Main
{
    public static void main(String[] args)
    {
        Scanner sc = new Scanner(System.in);
		int n = sc.nextInt();//总人数
		int m=3;//每隔3人杀死一个
		System.out.println(josephusBuRec(n,m));//输出最后活下来的人的初始位置下标
    }
    
	public static int josephusBuRec(int n,int m)
	{
		if(n == 1)
		{
			return 0;//直接可以保住性命,下标n为0
		}
		return (josephusBuRec(n-1,m) + m) % n;//可以找到此规律:一直加m,加到超过N了,取余,从余数得到的位置开始
	}
}

由键盘输入人数,输出最后幸存者初始位置的结果如下:
在这里插入图片描述

【华为上机题】

有一个数组a[N]顺序存放0~N-1,要求每隔两个数删掉一个数,到末尾时循环至开头继续进行,求最后一个被删掉的数的原始下标位置。以8个数(N=7)为例:{0,1,2,3,4,5,6,7},0->1->2(删除)->3->4->5(删除)->6->7->0(删除),如此循环直到最后一个数被删除。
在这里插入图片描述

//每组输入数据为一行一个整数n(小于等于1000),为数组成员数
//如果大于1000,对a[999]进行计算
import java.util.Scanner;
public class Main{
    public static void main(String[] args){
        Scanner sc = new Scanner(System.in);
        while(sc.hasNext())
        {
            int n = sc.nextInt();//人的个数
            if(n>1000){
                 n=999;
            } 
			int m=3;
            System.out.println(josepus(n,m));
       }
    }
    
    public static int josepus(int n,int m){
        if(n==1){
            return 0;
        }
        return (josepus(n-1,m)+m) % n;//可以找到此规律:一直加m,加到超过N了,取余,从余数得到的位置开始
    }
}

在这里插入图片描述

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值