JAVA求解约瑟夫环


1、引言

与前面我们介绍的大多数程序问题一样,约瑟夫环问题也是来自于一个故事。

这个故事发生在一个名叫约瑟夫的犹太人身上,据说在罗马人占领乔塔帕特后,39 个犹太人与约瑟夫及他的朋友躲到一个洞中,39个犹太人决定宁愿死也不要被敌人到,于是决定了一个自杀方式,41个人排成一个圆圈,由第1个人 开始报数,每报数到第3人该人就必须自杀,然后再由下一个重新报数,直到所有人都自杀身亡为止。

但是,但是,哈哈,这个时候人性的自私就出现了,约瑟夫和他的朋友都不想死,怎么办呢?这个时候,约瑟夫想到了一个问题,这样一直循环下来,肯定是有3个人坚持到最后的,那么只要保证自己和朋友在最后三个人中就行了,还要保证最后一个需要自杀的是另外的一个人?如何保证呢?经过计算,约瑟夫发现,如果自己和朋友分别站在第16个位置和第31个位置,就会避免自杀的命运。

但是,你知道这是怎么计算出来的么?今天,我们就让程序帮我们解决这个问题。


2、描述

通用型的约瑟夫环问题的描述是:由N个人围成一个圈,从K个人开始报数,到M值出圈,然后再从1开始报数,到M出圈,一直到所有人都出圈。

基于上面的描述,我们大概可以整理出约瑟夫环游戏的整体思路如下:

2.1 一群人围在一起坐成环状(如:N)

2.2 从某个编号开始报数(如:K)

2.3 数到某个数(如:M)的时候,此人出列,下一个人重新报数

2.4 一直循环,直到所有人出列,约瑟夫环结束


3、代码

在描述中,我们已经清晰了解到了整个程序的执行流程,已经类似于伪代码,这里我们直接写出代码,不再写伪代码了,大家见谅。

public class Josephus {
    public static int[] arrayOfJosephus(
                               int number, int per) {
        int[] man = new int[number]; 

        for(int count = 1, i = 0, pos = -1; 
                count <= number; count++) { 
            do { 
                pos = (pos+1) % number;  // 环状处理 
                if(man[pos] == 0) 
                    i++; 

                if(i == per) {  // 报数为3了 
                    i = 0; 
                    break; 
                } 
            } while(true); 

            man[pos] = count; 
        } 
        
        return man;
    }

    public static void main(String[] args) {
        int[] man = Josephus.arrayOfJosephus(41, 3);
        int alive = 3;
        
        System.out.println("约琴夫排列:"); 
        for(int i = 0; i < 41; i++) 
            System.out.print(man[i] + " "); 


        System.out.println("\nL表示3个存活的人要放的位置:"); 
        for(int i = 0; i < 41; i++) { 
            if(man[i] > alive) 
                System.out.print("D"); 
            else 
                System.out.print("L"); 

            if((i+1) % 5 == 0) 
                System.out.print("  "); 
        } 

        System.out.println();
    }
}

4、总结

在众多的编程问题中,很多都来自于数学游戏,而数学是计算机科学的基础工程。大家如果想学习一些常用的算法,可以去找找这样类似的书籍看看,自己亲自动手敲一下,相信会有很大的提高。

数学使人周密,祝大家学习愉快。


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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值