zoukankan      html  css  js  c++  java
  • 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越大时方法一的时间效率会更差。

  • 相关阅读:
    PHP+Ajax手机移动端发红包实例
    PHP+Ajax点击加载更多列表数据实例
    Thinkphp带表情的评论回复实例
    PHP+Mysql查询上一篇和下一篇文章实例
    PHP通过session判断防止表单重复提交实例
    PHP+Ajax微信手机端九宫格抽奖实例
    PHP+Ajax+plupload无刷新上传头像代码
    PHP原生开发的各大音乐平台API接口
    js 获取浏览器高度和宽度值(多浏览器)(转)
    NPOI、MyXls、Aspose.Cells 导入导出Excel(转)
  • 原文地址:https://www.cnblogs.com/zhanglei93/p/5978940.html
Copyright © 2011-2022 走看看