A股上市公司传智教育(股票代码 003032)旗下技术交流社区北京昌平校区

 找回密码
 加入黑马

QQ登录

只需一步,快速开始

林磊

初级黑马

  • 黑马币:

  • 帖子:

  • 精华:

© 林磊 初级黑马   /  2014-9-8 19:41  /  3344 人查看  /  10 人回复  /   1 人收藏 转载请遵从CC协议 禁止商业使用本文

5黑马币
用java实现的丢手帕问题,即有n个人围成圈,从第k个人开始从1报数,
报到第m个人时出局,从出局人的下一个开始从新报数,
报到第m个人时出局......如此循环直至最后一人出局

10 个回复

倒序浏览
  1. class Child {
  2. int no; //编号
  3. Child nextChileChild = null; //指向下一个人

  4. public Child(int no) {

  5. this.no = no;
  6. }

  7. }

  8. //链表类

  9. //环形链表
  10. class CycLink {

  11. //先定义一个指向链表第一个小孩的那个引用
  12. //指向第一个小孩的引用,不能动
  13. Child firstChild = null;
  14. Child temp = null;
  15. int len = 0;// 表示共有几个小孩
  16. int k;
  17. int m;

  18. //设置链表大小
  19. public void setLen(int len) {
  20. this.len = len;
  21. }

  22. public void setK(int k) {
  23. //设置第几个人开始数数
  24. this.k = k;
  25. }

  26. public void setM(int m) {
  27. //设置m
  28. this.m = m;
  29. }

  30. public void play() {
  31. //1找到开始数数的人
  32. Child temp = this.firstChild;
  33. for (int i = 1; i < k; i++) {
  34. temp = temp.nextChileChild;

  35. }
  36. //数M下
  37. while (this.len != 1) {
  38. for (int j = 1; j < m; j++) {
  39. temp = temp.nextChileChild;
  40. }
  41. Child temp2 = temp;// 找到要出圈的前一个小孩
  42. //讲数到M的小孩 退出圈
  43. temp2=temp2.nextChileChild;
  44. temp.nextChileChild=temp2.nextChileChild;
  45. System.out.println("现在出圈的是" + temp2.no);
  46. this.len--;
  47. }
  48. //打印最优一个小孩
  49. System.out.print("最后出圈的是:" + temp.no);
  50. }

  51. //初始化链表
  52. public void creatLink() {
  53. for (int i = 1; i <= len; i++) {

  54. if (i == 1) {
  55. //创建第一小孩
  56. Child child = new Child(i);
  57. this.firstChild = child;
  58. this.temp = child;
  59. } else {
  60. if (i == len) {
  61. Child child = new Child(i);
  62. temp.nextChileChild = child;
  63. temp = child;
  64. temp.nextChileChild = this.firstChild;

  65. } else {
  66. //继续创建小孩
  67. Child child = new Child(i);
  68. temp.nextChileChild = child;
  69. temp = child;
  70. }
  71. }

  72. }

  73. }

  74. public void show() {

  75. Child temChild = this.firstChild;
  76. do {
  77. System.out.println(temChild.no + "###");
  78. temChild = temChild.nextChileChild;
  79. } while (temChild != this.firstChild);
  80. }
  81. }

  82. //主方法类

  83. public class Demo4 {

  84. public static void main(String[] args) {
  85. CycLink cyclink =new CycLink();
  86. cyclink.setLen(17);
  87. cyclink.creatLink();
  88. //cyclink.setK(17);//17代表尾号//从1号开始念
  89. cyclink.setK(4);//4代表尾号//从5号开始念
  90. cyclink.setM(3);//输出念到3的人出圈
  91. cyclink.show();
  92. cyclink.play();
  93. }
  94. }
复制代码

评分

参与人数 1黑马币 +5 收起 理由
林磊 + 5 很给力!

查看全部评分

回复 使用道具 举报
这是当场就要回答出来吗?还是有考虑时间?
回复 使用道具 举报
这是数据结构里的问题
回复 使用道具 举报
这是一个经典题目,用户输入M,N值,从1至N开始顺序循环数数,每数到M输出该数值,直至剩下一个,求最后一个人编号。
约瑟夫环问题,我给出的解法有两种:
1. 建立一个有N个元素的循环链表,然后从链表头开始遍历并记数,如果计数i==m(i初始为1)踢出元素,继续循环,当当前元素与下一元素相同时退出循环,记录这个元素的初始编号就可以了,你自己实现吧,思路是这样的。
2.思想:归纳为数学性问题
无论是用链表实现还是用数组实现都有一个共同点:要模拟整个游戏过程,不仅程序写起来比较烦,而且时间复杂度高达O(nm),当n,m非常大(例如上百万,上千万)的时候,几乎是没有办法在短时间内出结果的。我们注意到原问题仅仅是要求出最后的胜利者的序号,而不是模拟整个过程。因此如果要追求效率,就要打破常规,实施一点数学策略。
为了讨论方便,先把问题稍微改变一下,并不影响原意:
问题描述:n个人(编号0~(n-1)),从0开始报数,报到(m-1)的退出,剩下的人继续从0开始报数。求胜利者的编号。
我们知道第一个人(编号一定是m%n-1) 出列之后,剩下的n-1个人组成了一个新的约瑟夫环(以编号为k=m%n的人开始):
  k  k+1  k+2  ... n-2, n-1, 0, 1, 2, ... k-2并且从k开始报0。
现在我们把他们的编号做一下转换:
k     --> 0
k+1   --> 1
k+2   --> 2
...
...
k-2   --> n-2
k-1   --> n-1
变换后就完完全全成为了(n-1)个人报数的子问题,假如我们知道这个子问题的解:例如x是最终的胜利者,那么根据上面这个表把这个x变回去不刚好就是n个人情况的解吗?!!变回去的公式很简单,相信大家都可以推出来:x'=(x+k)%n
如何知道(n-1)个人报数的问题的解?对,只要知道(n-2)个人的解就行了。(n-2)个人的解呢?当然是先求(n-3)的情况 ---- 这显然就是一个倒推问题!好了,思路出来了,下面写递推公式:
令f表示i个人玩游戏报m退出最后胜利者的编号,最后的结果自然是f[n]
递推公式
f[1]=0;
f=(f[i-1]+m)%i;  (i>1)
有了这个公式,我们要做的就是从1-n顺序算出f的数值,最后结果是f[n]。因为实际生活中编号总是从1开始,我们输出f[n]+1
由于是逐级递推,不需要保存每个f,程序也是异常简单:

  1. /*
  2. **  n表示人数,m表示每隔几个就出局
  3. */
  4. int getWinner_num(int n,int m)
  5. {
  6.     int s = 0;
  7.     for (int i = 2; i <= n; i++)
  8.     {
  9.         s = (s + m) % i;
  10.     }
  11.     return  s+1;
  12. }
复制代码







评分

参与人数 1黑马币 +2 收起 理由
林磊 + 2 赞一个!

查看全部评分

回复 使用道具 举报
这是我自己写的。题目类似,希望对你有用

//思路:定义一个int数组,容量为500,代表500个小朋友,数组中的所有元素的值都设为1,开始报数,报数到3的将该元素的值设为0,计算500元素的值和,当为1时,打印出编号。
class aaa
{
        public static void main(String[] args)
        {
                int i=1;
                int count=1;
                int[] array = new int[500];
                //赋值为1
                for(i=1;i<=500;i++)
                        array[i-1]=1;
                //当数组元素的和为1,则停止运行
                while(1!=sum(array))
                {
                        for(i=1;i<=500;i++)
                        {
                                //没有报过3的小朋友继续报数
                                if (array[i-1]==1)
                                {
                                        //让count在1-3循环
                                        if(count==4)
                                                count = 1;
                                        if(count==3)
                                                //报到3的退出
                                                array[i-1]=0;
                                        count++;
                                }
                        }
                }

                for(i=1;i<=500;i++)
                        if(array[i-1]==1)
                        System.out.print("最后一个小朋友是:"+i);
        }
        public static int sum(int[] array)
        {
                int len = array.length;
                int sum=0;
                for(int i=0;i<len;i++)
                        sum = sum + array[i];
                return sum;
        }
}
回复 使用道具 举报
学习了。
回复 使用道具 举报
daoqin 发表于 2014-9-9 22:34
这是一个经典题目,用户输入M,N值,从1至N开始顺序循环数数,每数到M输出该数值,直至剩下一个,求最后一个 ...

大神,经典~~~
回复 使用道具 举报
感觉会需要一些考虑时间
回复 使用道具 举报
我有一个简单的模型,用boolean [] 数组来来表示小孩围成的圈,然后开始全部true,然后数,数到指定数人变为false,再重新开始数,重复下去,碰到到最后一个,下标回到开始,最后找出剩下的最后一个true:
  1. public class countQuit {
  2.         public static void main(String[] args) {
  3.        
  4.                 boolean[] circle = new boolean[500];
  5.                 for(int i = 0;i < 500;i++) {
  6.                         circle[i] = true;
  7.                 }
  8.                
  9.                 int countNum = 0;
  10.                 int index = 0;
  11.                 int leftcount = circle.length;
  12.                
  13.                 while (leftcount > 1) {
  14.                         if(circle[index] == true) {
  15.                                 countNum++;       
  16.                         }
  17.                         if(countNum == 3) {
  18.                                 circle[index] = false;
  19.                                 countNum = 0;
  20.                                 leftcount--;                       
  21.                                 }
  22.                         index++;
  23.                         if(index == circle.length) {
  24.                                 index = 0;
  25.                                 }
  26.                 }
  27.                 for(int i = 0;i < circle.length;i++) {
  28.                         if(circle[i] == true) {
  29.                                 System.out.println(i);
  30.                         }
  31.                 }
  32.         }
  33. }
复制代码
回复 使用道具 举报
我是来学习的
回复 使用道具 举报
您需要登录后才可以回帖 登录 | 加入黑马