Java 约瑟夫环问题解决方案

1、问题描述

约瑟夫环(约瑟夫问题)是一个数学的应用问题:已知n个人(以编号1,2,3…n分别表示)围坐在一张圆桌周围。从编号为k的人开始报数,数到m的那个人出列;他的下一个人又从1开始报数,数到m的那个人又出列;依此规律重复下去,直到圆桌周围的人全部出列。通常解决这类问题时我们把编号从0~n-1,最后结果+1即为原问题的解。–百度百科

2、解决方案

  
  这里主要使用了LinkedList来存储所有人的信息,假设有n个人,编号为0-n-1,默认是从编号为0的第一个人开始报数,每次从List中取出第一个元素来,如果此时报的数是淘汰数字的整数倍,则将该元素淘汰掉,否则放到List的末尾中,循环执行这个过程直到List中的人数与要求结束的人数相等为止,返回List中的编号组成的数组即可。

3、代码实例


import java.util.LinkedList;
import java.util.Scanner;

/**
 * 约瑟夫环问题,输入总人数,每个人的编号从0开始,输入一个淘汰数字,当报数的人报的数为淘汰数字的整数倍数该人淘汰,后面的人继续报数(或从新报数是一样的)
 */
public class JosephDemo {

    private LinkedList<Integer> perList;
    private int start;
    private int scale;
    private int end;

    /**
     * @param num
     *            总人数,每个人的编号是从0开始的
     * @param start
     *            起始报数
     * @param scale
     *            报数为scale的整数倍时淘汰一个人,比如scale为3,则报数为3、6...的人会淘汰
     * @param end
     *            结束时剩余的人数
     */
    public JosephDemo(int num, int start, int scale, int end) {
        perList = new LinkedList<Integer>();
        for (int i = 0; i < num; i++) {
            perList.add(i);
        }
        this.start = start;
        this.scale = scale;
        this.end = end;
    }

    public static void main(String[] args) {

        Scanner scanner = new Scanner(System.in);

        System.out.print("请输入总人数,大于0的整数:");
        int num = scanner.nextInt();

        System.out.print("请输入淘汰数字,大于0的整数:");
        int scale = scanner.nextInt();

        System.out.print("请输入起始报数的编号,大于等于0的整数:");
        int start = scanner.nextInt();

        System.out.print("请输入结束时剩余的人数,大于0的整数:");
        int end = scanner.nextInt();

        long l = System.currentTimeMillis();
        JosephDemo yd = new JosephDemo(num, start, scale, end);
        Integer[] index = yd.findEnd();
        System.out.print("剩下的编号为:");
        for (int i = 0; i < index.length; i++) {
            System.out.println(index[i] + 1);
        }
        System.out.println("耗时:" + (System.currentTimeMillis() - l));
    }

    /**
     * 找到剩下输入的结束人数时的所有编号
     * 
     * @return
     */
    private Integer[] findEnd() {
        int lastNum = perList.size();
        int _start = this.start;
        while (lastNum != this.end) {
            Integer head = perList.pop();
            if (_start % scale == 0) {
                lastNum--;
            } else {
                perList.addLast(head);
            }
            _start++;
        }
        Integer[] result = perList.toArray(new Integer[0]);
        return result;
    }
}

执行的结果:

请输入总人数,大于0的整数:1000
请输入淘汰数字,大于0的整数:13
请输入起始报数的编号,大于等于0的整数:1
请输入结束时剩余的人数,大于0的整数:1
剩下的编号为:396
耗时:16
  • 1
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值