问题的描述
N个人,编号为1~N,从第一个人开始报数到M,报到M的人移除,剩下的人从被移除的人后面继续从一到M报数,报到M的移除,依次类推,求依次被移除的人的编号。
方法一
使用队列来解决。
因为我们处理的是n个元素里面的第m个元素,如果每次从队列里一边取元素,一边又加到队列的末尾,数到第m的时候,这第m的元素直接出队,不再入队。依此循环n遍,可以按所需顺序移除掉n个元素。
C++代码如下:
1 #include <iostream>
2 #include <stdlib.h>
3 using namespace std;
4
5 struct Node
6 {
7 int data;
8 struct Node* next;
9 };
10 typedef struct Node* queue;
11 typedef struct Node* position;
12 //创建队列
13 queue create_queue(int N)
14 {
15 queue Q = (queue)malloc(sizeof(Node));
16 Q->next = NULL;
17 position r=NULL;
18 for (int i = 1; i <= N; i++)
19 {
20 position p = (position)malloc(sizeof(Node));
21 p->data = i;
22 if (Q->next == NULL)
23 Q->next = p;
24 else
25 r->next = p;
26 r = p;
27 }
28 r->next = NULL;
29 return Q;
30 }
31 //出队
32 position Dequeue(queue Q)
33 {
34 if (Q->next == NULL)
35 {
36 cout << "queue is empty" << endl;
37 exit(1);
38 }
39 else
40 {
41 position front = Q->next;
42 Q->next = front->next;
43 front->next = NULL;
44 return front;
45 }
46 }
47 //入队
48 void Enqueue(queue Q,position p)
49 {
50 position r=Q;
51 position rear = (position)malloc(sizeof(Node));
52 if (rear == NULL)
53 {
54 cout << "out of space";
55 exit(1);
56 }
57 while(r ->next!= NULL)
58 r = r->next;
59 r->next = rear;
60 rear->data = p->data;
61 rear->next = NULL;
62 free(p);
63 }
64 //Josephus
65 void Josephus(queue Q, int N,int M)
66 {
67 position p,r=Q;
68 for (int i = 0; i <N; i++)//循环N次
69 {
70 for (int j = 0; j < M-1; j++)//出队和入队M-1次
71 {
72 p=Dequeue(r);//出队
73 Enqueue(r,p);//入队
74 }
75 p = Dequeue(r);//出队第M次结点,但不再入队
76 cout<<p->data<<" ";
77 }
78 }
79 int main()
80 {
81 queue Q=create_queue(10);
82 Josephus(Q,10,5);
83 system("pause");
84 return 0;
85 }
运行结果:

方法二
使用递归。
从数学的角度考虑,N个人围坐在一起,编号为0~N-1(注意这里从0开始编号),从中移除第M个人后,剩下的N-1个人从上一次被移除的人后面重新开始编号,即从0~N-2。依次类推,直至只剩下最后一个人,编号为0。举个例子,有5个人围坐在一起,M=4,编号变化情况如下:
5人 0 1 2 3 4
4人 1 2 3 0
3人 1 2 0
2人 0 1
1人 0
编号之间存在数学关系,
index(n)=(index(n-1)+M)%n
即某个人在n人环时的编号index(n)与其在n-1人环时的编号index(n-1)之间的关系。
还有个比较重要的信息,就是N人环中第一个被移除的人的编号必为(N+M-1)%N。N人环第二个被移除的人的编号可以从N-1人环第一个被移除的人的编号根据上述公式推出,N人环第三个被移除的人的编号可以从N-1人环第二个被移除的人的编号推出,而N-1人环第二个被移除的人的编号又可以从N-2人环第一个被移除的人的编号推出……依此类推可以求出N人环第k次被移除的人的编号。(一句话,N人环第二个被移除的人和N-1人环被移除的人是同一个人,只是编号不同,编号关系即为根据上述公式)
代码如下:
1 #include<iostream>
2 using namespace std;
3
4 int Josephus(int N,int M,int k)//计算出第k次被移出元素的编号
5 {
6 if (k == 1)
7 return (N + M - 1) % N;
8 else
9 return (Josephus(N - 1, M, k - 1) + M) % N;
10 }
11 int main()
12 {
13 for (int k = 1; k <=5; k++)
14 cout << Josephus(5, 4, k)+1 << " ";//加1是为了使编号是从1开始而不是0
15 system("pause");
16 return 0;
17 }
运行结果:

来源:https://www.cnblogs.com/cs0915/p/12152078.html