• 约瑟夫问题及扩展问题的代码实现


    下面两个博客的内容给了我很大的帮助,基本上都是参考他们的内容。

    http://blog.csdn.net/u013850478/article/details/23037423 

    http://blog.sina.com.cn/s/blog_3cb8b94501017lpr.html

    首先约瑟夫的基本问题里,可以推导出递推公式,有一个递推方法比较详细,忘了在哪个博客上看到的,我只是复述一遍,过程如下图:

    有了递推公式,解决基本问题(最后一个人的编号,过程不需要输出)就是轻而易举的事。

    下面代码包括几个方法,分别是:

    解决基本问题,O(n)时间复杂度,编号从0开始;

    解决基本问题,O(n)时间复杂度,编号从1开始;

    解决基本问题,O(NM)时间复杂度,编号从0开始,采用环模拟报数的过程,不过这种方法可以输出依次出队的编号(我有个疑问是,如果要依次输出出队编号的话,还有什么更有效的方法);

    扩展问题1,当首次报到m出队和之后报到k出队的m和k不同时;

    扩展问题2,第P个出队的编号是多少;

    扩展问题3,结合扩展问题1和扩展问题2的情况;

    扩展问题4,当M=2时,这种特殊情况下,复杂度可降到O(logN),不过我的代码用了递归,没有直接用迭代,不知道用迭代怎么把这个问题写出来;

      1 package Source;
      2 class circleNode{
      3     int data;
      4     circleNode next;
      5     public circleNode(int _data, circleNode n){
      6         data = _data;
      7         next = n;
      8     }
      9 }
     10 /**
     11  * 从0开始编号的地推公式:f(n,m) = [f(n-1,m)+m]%n ; f(1,m) = 0;
     12  * 从1开始编号的递推公式:f(n,m) = [f(n-1,m)+m -1]%n +1; f(1,m) = 1;
     13  * @author Echo
     14  *
     15  */
     16 public class CircleNM {
     17     /**
     18      * 约瑟夫问题的基本问题:n个人围成一圈,从0开始编号到n-1,从1报数到m,数到m的出队,然后从下一个开始数1,报到m的输出队列,
     19      * 求最后一个人的编号。
     20      * 这里采用数学方式f(n,m) = [f(n-1,m)+m]%n  O(n)
     21      * 如果编号是从1开始,则最后输出的时候加1
     22      * 采用递推的方法解决
     23      * @param n
     24      * @param m
     25      * @return
     26      */
     27     public static int firstMathMethod(int n,int m)
     28     {
     29         if(n<=0 || m<=0)
     30             return -1;//输入参数不对
     31         int lastVal = 0;
     32         for(int i=2;i<=n;i++)
     33             lastVal = (lastVal+m)%i;
     34         return lastVal;
     35     }
     36     public static int firstMathMethod2(int n,int m)
     37     {
     38         if(n<=0 || m<=0)
     39             return -1;//输入参数不对
     40         int lastVal = 1;
     41         for(int i=2;i<=n;i++)
     42             lastVal = (lastVal+m-1)%i +1;
     43         return lastVal;
     44     }
     45     /**
     46      * 问题同上,但是用链表
     47      * 这种方法可以输出依次出队的编号,目前我不知道除了模拟方法,还有什么更有效率的方法可以依次输出这个顺序??
     48      * 采用环模拟删除过程 O(nm)
     49      * @param n
     50      * @param m
     51      * @return
     52      */
     53     public static int secondLinkedListMethod(int n, int m)
     54     {
     55         //创建环形
     56         circleNode head = new circleNode(0,null);
     57         circleNode pointer =head;
     58         for(int i=1;i<n;i++)
     59         {
     60             pointer.next = new circleNode(i,null); 
     61             pointer = pointer.next;
     62         }
     63         pointer.next = head;
     64         //模拟删除过程
     65         pointer = head;
     66         int index = 1;
     67         while(pointer.next!=pointer)
     68         {
     69             if(index == m-1)
     70             {
     71                 pointer.next = pointer.next.next;
     72                 pointer = pointer.next;
     73                 index = 1;
     74             }else
     75             {
     76                 index++;
     77                 pointer =  pointer.next;
     78             }
     79         }
     80         return pointer.data;
     81         
     82     }
     83     
     84     /**
     85      * 这算是约瑟夫问题的一个扩展:n 个人按顺时针围成一圈从1开始按顺序顺序编号,首先先把第m号的人出队,
     86      * 然后从m+1号开始按1、2、3 、....、k按顺时针报数,报 k 者退出圈外,
     87      * 其余的人再从1、2、3 、....、k 报数,报 k 的人再退出圈外,依次类推。请输出最后一个人的原序号。
     88      * 其实整个思维过程和基本问题是一制的。
     89      * @param n 如果编号从1开始,则 最后输出的数+1 即可
     90      * @param k
     91      * @param m
     92      * @return
     93      */
     94     public static int genericNMK(int n, int k, int m)
     95     {
     96         if(n<=0 || m<=0)
     97             return -1;//输入参数不对
     98         int lastValue = 0;
     99         for(int i=2;i<n;i++)
    100             lastValue = (lastValue + k)%i;
    101         return (lastValue +m)%n;
    102     }
    103     142     /**
    143      * 扩展问题2:第P轮出圈的编号,这个r初始的时候为什么是0,我不懂???
    144      * 这里是从1开始编号
    145      * @param n
    146      * @param m
    147      * @param p
    148      * @return
    149      */
    150     public static int NMP(int n,int m, int p)
    151     {
    152         int r = 0;
    153         for(int i=n-p+1;i<=n;i++)
    154         {
    155             r = (r+m-1)%i +1;
    156         }
    157         return r;
    158     }
    159     /**
    160      * 扩展问题3,首次出队的报道数和之后的不同
    161      * @param n 从1开始编号到n
    162      * @param m 除了首次外都按照
    163      * @param k 首次出队的编号是报道k的
    164      * @param p 第p个出圈
    165      * @return
    166      */
    167     public static int NMKP(int n,int m,int k, int p)
    168     {
    169         int r = 0;
    170         for(int i=n-p+1;i<n;i++)
    171         {
    172             r = (r+m-1)%i +1;
    173         }
    174         return (r+k-1)%n+1;
    175     }
    176     /**
    177      * 一种特殊情况下,即m=2时,可以得到O(logN)的算法
    178      * 可以再想下直接迭代怎么做??
    179      * 采用递归的方式解决上面的特殊问题
    180      * @param n
    181      * @return
    182      */
    183     public static int N2recu(int n)
    184     {
    185         if(n<=0)
    186             return -1;
    187         if(n == 1)
    188             return 1;
    189         if(n%2 == 0)
    190             return 2*N2recu(n/2)-1;
    191         else
    192             return 2*N2recu(n/2)+1;
    193     }
    194     /**
    195      * @param args
    196      */
    197     public static void main(String[] args) {
    198         // TODO Auto-generated method stub
    199         //System.out.println(firstMathMethod(10,11));
    200         //System.out.println(firstMathMethod2(10,11));
    201         //System.out.println(secondLinkedListMethod(8,3));
    202         
    203         System.out.println(N2recu(11));
    204     }
    205 
    206 }
    有问题可以和我联系,bettyting2010#163 dot com
  • 相关阅读:
    自定义类型
    基本类型
    个人的职业规划
    FastDFS .Net客户端使用指南
    Delphi中资源的简单应用
    GridView数据绑定
    GridView的分页功能
    硬盘最多能分几个区?
    C#中public、private、protected、internal、protected internal
    2007.10.09错误记录
  • 原文地址:https://www.cnblogs.com/echoht/p/3674795.html
Copyright © 2020-2023  润新知