Josephus问题的实现

问题的描述

N个人,编号为1~N,从第一个人开始报数到M,报到M的人移除,剩下的人从被移除的人后面继续从一到M报数,报到M的移除,依次类推,求依次被移除的人的编号。

方法一 

使用队列来解决。

因为我们处理的是n个元素里面的第m个元素,如果每次从队列里一边取元素,一边又加到队列的末尾,数到第m的时候,这第m的元素直接出队,不再入队。依此循环n遍,可以按所需顺序移除掉n个元素。

C++代码如下:

 1 #include 
 2 #include 
 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次
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<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
 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 }

运行结果:

你可能感兴趣的:(Josephus问题的实现)