java约瑟夫环逻辑_趣味算法--约瑟夫环问题

问题描述

已知n个人(以编号1,2,3,...,n分别表示)围坐在一张圆桌上。指定编号为k的人开始从1报数,数到m的那个人出列;出列那个人的下一位又从1开始报数,数到m的那个人出列;以此规则重复下去,直到圆桌上的人全部出列。

分析解决

解决方法主要有逻辑分析、数学分析法。

逻辑分析:就是按照游戏规则一个个报数,报到m的人出局,结构层次简单清晰明了。这种方式实现主要采用顺序表实现

数学分析:采用数学方式归纳统计分析出每次出局人的规律,直接得出每次出局的人,然后以代码实现。这种方法需要较强的数学分析能力,代码较简单。这种实现主要采用数学公式。

逻辑分析

先以C语言数组为例,由于C语言数组不能像Java、Python这种面向对象语言的数组那样使用删除数组元素的方法,每次删除数组中的一个元素,都要将后面元素前移一位,这里简单的将删除的元素值设为0。

假设总人数n=7,从编号k=2的人开始,数到m=3的人出局,下面是分析过程。

java约瑟夫环逻辑_趣味算法--约瑟夫环问题_第1张图片

8f900a89c6347c561fdf2122f13be562.png

961ddebeb323a10fe0623af514929fc1.png

1 #include

2

3 int main(void)4 {5 int total; //define total people

6 int out; //define out number

7 int start; //define start number

8

9 /*set the total, out and start number*/

10 printf("Please enter the total people\n");11 scanf("%d", &total);12 printf("Please enter the out number\n");13 scanf("%d", &out);14 printf("Please enter the start position\n");15 scanf("%d", &start);16

17 int people[total]; //init the people

18 int i = start - 1; //init i for people tag

19 int count = 0; //init count for the people out

20 int remain = total; //init the remain number of people

21

22 /*init josephus ring*/

23 int j = 0;24 for (j = 0; j < total; j++)25 people[j] = j + 1;26

27 /*begin to solve josephus problem*/

28 printf("begin to solve josephus's problem.\n");29 /*print josephus ring*/

30 for (j = 0; j < total; j++)31 printf("%d", people[j]);32 printf("\n");33

34 while (1)35 {36 if(people[i] > 0)37 {38 count++;39 }else

40 {41 i++;42 if (i ==total)43 i = 0;44 continue;45 }46

47 if(count == out)48 {49 printf("The people of %d is out.\n", people[i]);50 people[i] = 0;51 count = 0;52 remain--;53 }54

55 i++;56 if (i ==total)57 i = 0;58

59 if (remain == 0)60 break;61

62 }63

64 printf("Josephus has solved his problem\n");65

66 return 0;67 }

C 数组版

运行后,结果与上面分析一致

java约瑟夫环逻辑_趣味算法--约瑟夫环问题_第2张图片

下面给出Java的集合对象实现和Python的列表实现。因为Java集合对象和Python列表都有删除元素的方法,这里的逻辑和上面稍有不同。

这里配的图第5个出列后面解释有点错误,大概的意思和第二个出列的处理类似。

java约瑟夫环逻辑_趣味算法--约瑟夫环问题_第3张图片

8f900a89c6347c561fdf2122f13be562.png

961ddebeb323a10fe0623af514929fc1.png

1 importjava.util.Scanner;2 importjava.util.ArrayList;3 importjava.util.List;4

5 public classJOSEPHUS {6

7 public static voidmain(String[] args) {8 /*init data*/

9 Scanner scanner = newScanner(System.in);10 System.out.println("Please enter the total people");11 int total =scanner.nextInt();12 System.out.println("Please enter the out number");13 int out =scanner.nextInt();14 System.out.println("Please enter the start position");15 int start =scanner.nextInt();16

17 int count = 0; //define count for people

18

19 /*init josephus ring and print it*/

20 List people = new ArrayList();21 for (int i = 0; i < total; i++)22 people.add(i + 1);23 System.out.println(people);24

25 int now = start - 1; //Pointer of people who count

26

27 /*Begin to solve josephus problem*/

28 while(people.size()>0) {29 count++;30 if(count ==out) {31 System.out.println("The people of " + people.get(now) + " is out");32 people.remove(now);33 //System.out.println(people);

34 if (now ==people.size())35 count = 0;36 else

37 count=1;38 }39

40 now++;41 if(now >=people.size())42 now = 0;43 }44 }45 }

java集合版

代码运行结果与分析一致,java集合版比C数组版逻辑处理代码稍微简单一点点。

java约瑟夫环逻辑_趣味算法--约瑟夫环问题_第4张图片

8f900a89c6347c561fdf2122f13be562.png

961ddebeb323a10fe0623af514929fc1.png

1 total = int(input("请输入总人数:"))2 out = int(input("请输入出局号:"))3 start = int(input("请输入开始位置:"))4

5 #初始化约瑟夫环

6 people =[]7 for i inrange(total):8 people.append(i+1)9

10 print("需要处理的约瑟夫环为:\n",people)11 count = 0 #定义报数变量

12 now = start - 1 #now指定当前报数的人

13 whilelen(people):14 count += 1

15 if(count ==out):16 print("编号为 %d 的人出局" %people[now])17 people.pop(now)18 if now ==len(people):19 count =020 else:21 count = 1

22 now += 1

23 if now >=len(people):24 now = 0

Python列表版

java约瑟夫环逻辑_趣味算法--约瑟夫环问题_第5张图片

运行结果与分析一致,可以看出C、java和Python用数组实现约瑟夫环,Python的代码是最短的,C的代码最长,Java居中。当然代码都还有优化的地方。

也可以使用环形链表实现。

数学分析

总人数有n个人,从k的位置开始报数,报数到m的人出局。

先假设人数n足够大,不管出局多少个人,都不会回到编号为1的位置。

第一次出局的人的位置为k-1+m,出局人的下一位从新开始报数,这就成了一个新的约瑟夫环,相当于第二次报数的起始位置从k+m开始,总人数为n-1;

第二次出局的人的位置为k+m-1+m,出局人的下一位从新开始报数,这就又成了一个新的约瑟夫环,相当于第三次报数的起始位置从k+2m开始,总人数为n-2;

第三次出局的人的位置为k+2m-1+m,出局人的下一位从新开始报数,这就又成了一个新的约瑟夫环,相当于第四次报数的起始位置从k+3m开始,总人数为n-3;

。。。

第t次出局的人的位置为k+tm-1,出局人的下一位从新开始报数,这就又成了一个新的约瑟夫环,相当于第t+1次报数的起始位置从k+tm开始,总人数为n-t。

因为假设人数n足够大,不管出局多少个人,都不会回到编号为1的位置,相当与出局后又成了一个新的约瑟夫环,所以(k+tm-1)%(n-t)=(k+tm-1)为出局人的位置。

现在假设k-1+m>n

当编号n报数时还没有报到m,则从编号1接着编号n报数,相当与n后面还是接着无穷无尽等待报数的人。

假设循环c轮,编号p,报的数是m,编号p要出局,相当于k-1+m=cn+p,即(k-1+m)%cn=p,剩余的人数为n-1。

按上面的方法很容易得出第t次出局的人的编号为(k+tm-1)%(n-t)。

当k-1+m=n时

即编号为n的人报数为m,此时(k+tm-1)%(n-t)=0,重新开始的位置为编号为1的位置。

8f900a89c6347c561fdf2122f13be562.png

961ddebeb323a10fe0623af514929fc1.png

1 packageyuesefu;2 importjava.util.ArrayList;3 importjava.util.List;4 importjava.util.Scanner;5

6 public classYue {7 public static voidmain(String[] args) {8 Scanner scanner = newScanner(System.in);9 System.out.print("请输入总人数:");10 int total =scanner.nextInt();11 System.out.print("请输入出局号:");12 int count =scanner.nextInt();13 System.out.print("请输入开始的编号:");14 int start =scanner.nextInt();15

16 /*初始化约瑟夫环*/

17 List people = new ArrayList();18 for (int i = 1; i <= total; i++) {19 people.add(i);20 }21 int k=start-1;22 System.out.println("约瑟夫环为:"+people);23 while (people.size()>0) {24 k = (k + count)%(people.size())-1;25 if(k<0) {26 System.out.println("出局人的编号为:" + people.get(people.size()-1));27 people.remove(people.size()-1);28 k=0;29 }else{30 System.out.println("出局人的编号为:" +people.get(k));31 people.remove(k);32 }33 }34 }35 }

Java 实现

8f900a89c6347c561fdf2122f13be562.png

961ddebeb323a10fe0623af514929fc1.png

1 total = int(input("请输入总人数:"))2 out = int(input("请输入出局号:"))3 start = int(input("请输入开始位置:"))4

5 #初始化约瑟夫环

6 people =[]7 for i inrange(total):8 people.append(i+1)9

10 print("需要处理的约瑟夫环为:\n",people)11 now = start - 1 #now指定当前报数的人

12 whilelen(people):13 now = (now + out)%len(people)-1

14 if now <0:15 print("编号为 %d 的人出局" %people[now])16 people.pop(now)17 now =018 else:19 print("编号为 %d 的人出局" %people[now])20 people.pop(now)

Python实现

java约瑟夫环逻辑_趣味算法--约瑟夫环问题_第6张图片

测试的结果也是和前面的测试结果一样的,可以看到后面程序处理更简单些,省了很多逻辑判断环节,这就是数学的魅力。

你可能感兴趣的:(java约瑟夫环逻辑)