• Josephus环问题



    约瑟夫环问题


    • 问题描述:

    Josephus问题可以描述为如下的一个游戏:N个人编号从1到N,围坐成一个圆圈,从1号开始传递一个热土豆,经过M次传递后拿着土豆的人离开圈子,由坐在离开的人的后面的人拿起热土豆继续进行游戏,直到圈子只剩下最后一个人。例如:M=0,N=5,则游戏人依次被清除,5号最后留下;如果M=1,N=5,那么被清除的人的顺序是2,4,1,5,最后剩下的是3号。

    • 如下是两种解题方法:

      • 建立一个N大小的数组,存储N个人是否还在圈子内(0为在圈子内,-1为已经离开圈子),依次循环遍历整个数组,直到剩下的人数(left)为1。
      •   public static void pass(int m, int n){
                int[] num = new int[n];
                int left = n;  //剩下的人数
                int index = 0; //当前遍历到的位置
                while(left != 1){
                    for(int i = 0; i< m; i++){
                        if(num[index++] != 0)   //如果当前人已经清除
                            i--;
                        if(index >= n)
                            index = 0; 
                    }
                    while(num[index] != 0){
                        index++;
                        if(index >= n)
                        index = 0;
                    }
                    System.out.println("out number is " + (index + 1));
                    num[index] = -1;    //将清除的数据下标置-1
                    index++;
                    if(index >= n)
                        index = 0;
                    left--;
                }
            }
      • 第二种方式,将1~N的数添加到一个ArrayList对列中,首先计算偏移量(mPrime),当mPrime小于对列长度的一半时,则从前往后依次遍历找到清除的元素;当mPrime大于对列长度的一半时,从后往前遍历找到清除的元素。
      • public static void pass2(int m, int n){
                ArrayList<Integer> list = new ArrayList<Integer>();
                for(int i = 1; i <= n; i++)
                    list.add(i);
                ListIterator<Integer> iter = list.listIterator();
                int left = n;    //剩下的人数
                int item = 0;    //the out number
                for(int i= 1; i < n; i++){
                    int mPrime = m % left;
                    if(mPrime < left/2){     //如果当前的偏移量小于list长度的一半时
                        if(iter.hasNext())
                            item = iter.next();
                        for(int j = 0; j < mPrime; j++){
                            if(!iter.hasNext())
                                iter= list.listIterator();
                            item = iter.next();
                        }
                    }
                    else{  //当偏移量大于list长度的一半时,从后往前找
                        for(int j = 0; j< left - mPrime; j++){
                            if(!iter.hasPrevious())
                                iter = list.listIterator(list.size());
                            item = iter.previous();
                        }
                    }
                    System.out.println("out number is " + item);
                    iter.remove();
                    if(!iter.hasNext())    //有可能下一次循环mPrime就会小于left的一半
                        iter = list.listIterator();
                    left--;
                }
            }
    • 总结

    当M,N较大时,则第二种方法时间效率更高,实现表明,当N=100000,M=9000时(省略的两个算法中的syso语句),方法一个执行时间是30713ms,而第二种方法的执行时间仅为4891ms,M越大时方法一的时间效率会更差。

  • 相关阅读:
    extjs使用笔记-21
    如何安装整个linux系统中所需要的mp3播放库插件? 可以在安装rpmfusion仓库后直接通过dnf install进行按照就可以了
    aria2的下载配置
    再谈fedora23下Virutalbox的安装. --问题的关键在于 安装kernel-devel包
    extjs的使用笔记2
    提高迅雷的下载速度
    extjs的使用笔记
    expr的字符串操作 表达式: length, index, match, substr等
    弄懂linux shell对包含$的变量的执行过程?
    从0开始安装fedora23的笔记-- 以及使用fedora的常规问题-3
  • 原文地址:https://www.cnblogs.com/zhanglei93/p/5978940.html
Copyright © 2020-2023  润新知