约瑟夫环代码展示,以及理解约瑟夫环


本人也是刚刚接触算法,如果有不准确的地方,欢迎大家留言评论,一起学习,一起进步,奥利给!

约瑟夫环的简单的图例(画的太抽象,大家理解下,我有必要去学学画画了!)

约瑟夫环的原理

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;
    }
}

小剧场:几日不见,甚是想念啊