本人也是刚刚接触算法,如果有不准确的地方,欢迎大家留言评论,一起学习,一起进步,奥利给!
约瑟夫环的简单的图例(画的太抽象,大家理解下,我有必要去学学画画了!)
约瑟夫环的原理
1、一群人围在一起坐成环状(如:N)
2、从某个编号开始报数(如:K)
3、数到某个数(如:M)的时候,此人出列,
4、一直循环,直到所有人出列
不够清晰的话,可以看我上边优秀的画图,一群人N指的就是11,摸个编号开始报数K指的就是数字1(但是记住,他的下标是0哦~~~~~~~~),第一次数到某个数指的就是3,第二次数到某个数指的是6,以此类推哦----------,一直循环,直到所有的人都出列指的是N变为0,就是没人了,出列也就出完了。
简单的约瑟夫环问题(1)
已知n个人(以编号1,2,3…n分别表示)围坐在一张圆桌周围。从编号为k的人开始报数,数到m的那个人出列;他的下一个人又从1开始报数,数到m的那个人又出列;依此规律重复下去,直到圆桌周围的人全部出列。通常解决这类问题时我们把编号从0~n-1(指的是下标),最后 结果+1(因为我们找的是下标对应的这个数,所以要加 1 哦)即为原问题的解。
代码分析
1 2 3 4 5 6 7 8 9 10 11 12 13 14 | import java.util.Scanner; public class 约瑟夫环 { public static void main(String[] args) { Scanner sc = new Scanner(System.in); int n = sc.nextInt() int k = sc.nextInt(); int p = 0; for (int i = 2; i <= n; i++) { p = (p + k) % i; } System.out.println(p + 1); } } |
约瑟夫环最经典的问题(2)
据说著名犹太历史学家 Josephus有过以下的故事:在罗马人占领乔塔帕特后,39 个犹太人与Josephus及他的朋友躲到一个洞中,39个犹太人决定宁愿死也不要被敌人抓到,于是决定了一个自杀方式,41个人排成一个圆圈,由第1个人开始报数,每报数到第3人该人就必须自杀,然后再由下一个重新报数,直到所有人都自杀身亡为止。然而Josephus 和他的朋友并不想遵从。首先从一个人开始,越过k-2个人(因为第一个人已经被越过),并杀掉第k个人。接着,再越过k-1个人,并杀掉第k个人。这个过程沿着圆圈一直进行,直到最终只剩下一个人留下,这个人就可以继续活着。问题是,给定了和,一开始要站在什么地方才能避免被处决?Josephus要他的朋友先假装遵从,他将朋友与自己安排在第16个与第31个位置,于是逃过了这场死亡游戏。
看完这道题我的第一反应居然不是去解题,而是感慨,那个人真是编程天才,机智的一批,更想说的是不要仅仅指望知识来吃饭,关键时刻,知识能救命的呀!
题目分析
把这道题上相应的数字带入到上面约瑟夫环的原理的分析中。
代码分析,代码学习的位置、https://blog.csdn.net/weixin_43570367/article/details/105896737?utm_source=app
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 | package 约瑟夫环问题; import java.util.Scanner; public class 约瑟夫环问题 { public static void main(String [] args) { Scanner sc = new Scanner(System.in); int n = sc.nextInt(); if(n<2) { System.out.println("请您输入大于二的数字:"); return ; } //构建链表并获取头结点,把头节点赋值给currentNode Node currentNode = buildData(n); //用来计数 int count =0; //循环链表当前节点的上一个节点 Node beforeNode = null; //循环遍历列表 while(currentNode!= currentNode.next) { count++; if(count == 3) { //向后移动节点 beforeNode.next = currentNode.next; System.out.println("出环的标号是:"+ currentNode.data); count = 0; currentNode = currentNode.next; }else { //向后移动节点 beforeNode = currentNode; currentNode = currentNode.next; } //表示只有两个节点了,不在进行出环操作 if(beforeNode.data == currentNode.next.data) { break; } } System.out.println("最后留在环中的标号是:"+currentNode.data+ ","+ currentNode.next.data); } /* * 构建单项循环链表 * @param n 人数 * * @return返回头节点 * */ private static Node buildData(int n) { //循环链表的头节点 Node head = null; //循环链表当前节点的前一个节点 Node prev = null; for(int i=1; i<=n ; i++) { Node newNode = new Node(i); //如果是第一个节点 if(i == 1) { head = newNode; prev = head; //跳出当前循环,进行下一次循环 continue; } //如果不是第一个节点 prev.next = newNode; prev = newNode; //如果是最后的一个节点 if(i == n) { prev.next = head; } } return head; } } class Node{ //当前存储的数据 int data; Node next; //当前节点的下一个节点 public Node(int data) { this.data = data; } } |
小剧场:几日不见,甚是想念啊