The chain list solution, array solution and mathematical formula solution of Joseph Ring
Joseph Ring (Josephus) was raised by ancient Roman historian Joseph Josephus, who participated in and recorded the uprising of the Jews against Rome in the year 66-70. Joseph, as a general, managed to hold the city of Juda for 47 days, and after the fall of the city, he and 40 diehard soldiers took refuge in a nearby cave. There, the rebels voted to say "surrender or death." So Joseph suggested that everyone take turns to kill the person next to him, and this order was decided by lots. Joseph had deliberately caught the last sign and, as one of the two survivors of the cave, persuaded his former victim to surrender to Rome.
Joseph Ring the specific description of the problem is: with a number of 1,2,......,n N (n>0) individuals in a circle, from the 1th person began to count, report m when the stop Count, reported m of the people out of the circle, and then from his next person to re-count, report m stop Count, reported m out of the ring, ... Until everyone is out of the loop. After any given N and M, the design algorithm asks for the order of the n person out of the loop.
Solution one: Using circular chain list to realize
#Include<stdio.h>#Include<stdlib.h>typedefstructnode{int data;structNode *Next;} Node;/** * @ function Joseph Ring * @ parameter total: number of people * @ parameter from: The first person to count off * @ parameter counts: The number of Dequeue shouted * @ author Zheng * @ Update 2013-12-5 */voidJOSEPHUS(int Total,int from,int count) {Node *p1, *head; head =NULL;int i;Set up a circular link listfor (i =1; I <= total; i++) {Node *newnode = (node *)mallocsizeof (Node)); Newnode->data = i;IfNULL = = head) {head = NewNode;}else {p1->next = NewNode;} p1 = NewNode; } P1->next = head;Tail node connected to the head junction, so that the whole list loop up P1 = head;Make Pcur point to head nodeMove the current pointer pcur to the first oneIf the first person starts to count, this paragraph can not befor (i =1; I < from; i++) {p1 = p1->next;} Node *P2 =NULL;To delete a node in a queue that is reporting countwhile (p1->next! = p1) {for (i =1; I < count; i++) {p2 = p1; p1 = p1->next;} p2->next = p1->next;printf ("Delete number:%d\n", p1->data); //Print the data for the node to be deleted free (p1); //Delete node, frees the memory space occupied by the node from memory P1 = p2->next; The //P1 pointer points to the new node P2->next, which is the original P1->next} printf ("The last one is no.%d\n", p1->data);} int main() { int total, from, count; scanf ("%d%d%d", &total, &from, &count); JOSEPHUS (Total, from, count); return 0;}
Operation Result:
13 1 3Delete number: 3Delete number: 6Delete number: 9Delete number: 12Delete number: 2Delete number: 7Delete number: 11Delete number: 4Delete number: 10Delete number: 5Delete number: 1Delete number: 8The last one is No.13
Solution Two: Array implementation
Idea: Set the array A has n variables, each variable in the initial number of IDs is 1, indicating that the person in the queue, if the number of out-of-line identification becomes 0.
Now the counter starts at 1 and the accumulator is incremented by 1 for each reported number. Here the accumulator indicates the number of numbers. When tired to M, the number of people to be out of the column, the mark to become 0. The next person starts to count back from 1.
After the last person, from the first person began to count.
#Include<stdio.h>#Include<memory.h>IntMain(){int n, m;scanf"%d%d", &n, &m);int Flag[n +1];Marked as 1 in the queue, 0 for the dequeuememset (Flag,0,sizeof (flag));Set each element of the array to 0, declared in Memory.hint i =0;int outcnt =0;Number of people who record the dequeueint Numoff =0;CountMarked as 1 by defaultfor (i =1; I <= N; i++) {Flag[i] =1; }while (Outcnt < n-1) {for (i = 1; I <= n; i++) { if (1 = = Flag[i]) {numoff++; if (Numoff = = m) { printf ("dequeue:%d\n", i); outcnt++; flag[i] = 0; //The person who has been checked out is marked as 0 Numoff = 0; //Count off from scratch}} }} for (i = 1; I <= n; i++) { if (1 = = Flag[i]) { printf ("The last one is:%d\n", i);}} return 0;}
Operation Result:
13 3Dequeue:3Dequeue:6Dequeue:9Dequeue:12Dequeue:2Dequeue:7Dequeue:11Dequeue:4Dequeue:10Dequeue:5Dequeue:1Dequeue:8The last one is: 13
Solution three: Solving with mathematical formula
The program of the solution Joseph Ring above simulates the whole process of counting off, because N and M are relatively small, the program run time is acceptable, and the results can be calculated quickly. However, when the total number of participants n and the value m is very large, its operation speed is slow down. For example, when the value of n is millions, and M is tens of thousands of, it will take tens of thousands of cycles (determined by the number of M) to determine the number of the next dequeue in 2, although only 2 are left. Obviously, in the execution of this program, many steps are repeated useless loops.
So, can you design a more efficient program?
Way of course there is. Among them, in Joseph Ring, just need to ask out the last one of the first number of a row, and do not have to simulate the whole process. Therefore, in order to pursue the efficiency, we can consider from the mathematical point of view, find out the law and then write the program.
In order to discuss the convenience, first of all, according to the original intention to describe the problem in mathematical language.
Problem: will be numbered 0~ (n–1) This N person to arrange round, clockwise from 0 start count, report m–1 people exit circular queue, the remainder continues to count from 0, repeated. The number of the last dequeue in the circular queue was obtained.
The following first lists the original numbers of 0~ (N-1) for this N person as follows:
0 1 2 3 ... N-3 N-2 N-1
According to the previously deduced process, it is known that the number of the first dequeue must be (m–1)%N. For example, in 13 persons, if the person reporting 3 is out of the box, then the number of the first dequeue must be (3–1)%13=2, note that the number is starting from 0, so the number 2 actually corresponds to 1 as the starting point of the number 3. According to the previous description, the previous element of M (m–1) has been dequeue, then the list of 1 people is as follows:
0 1 2 3 ... M-3 m-20m m+1 m+2 ... N-3 N-2 N-1
Note that the above circle indicates the number of deletions.
According to the rules, when someone is out of the box, and the next position is counted from 0, the above list can be adjusted to the following form (that is, starting with the M position, and then connecting 0, 1, 2 ..., n–1, ...) to form a ring:
M m+1 m+2 ... N-2 N-1 0 1 ... M-3 M-2
The following relationship can be obtained by renumbering from 0 in the order listed above:
M m+1 m+2 ... N-2 N-1 0 1 ... M-3 M-2
0 1 2 ... N-(m+2) n-(m+1) n-m N-(M-1) ... N-3 N-2
Here, assuming that the number of the previous row is x and the number of the next line is Y, the corresponding relationship is:
y = (x - M + N) % N 公式【1】
Or
x = (y + M) % N 公式【2】
Through the conversion of the above table, the data after 1 people were re-organized into a 0~ (n–2) A total of n–1 personal list, continue to seek n–1 participants, according to the count to m–1 that is out of the queue, the last one to solve the first number in the circular queues.
See what the law is? The scale of the problem is reduced by a single process. That is, the problem of N personal count off, can be decomposed into the first to solve (n–1) personal count of the sub-problem, and for (n–1) personal count of sub-problem, can be decomposed into first [(N-1)-1] personal count of the sub-problem, ....
What is the hour of scale in the problem? is only 1 person (n=1), Count to (m–1) of the person out, then the final out of who? Of course only the person numbered 0. Therefore, the following functions can be provided:
F(1) = 0
Then, when n=2, Count to (m–1) of the person out of the end, who is the last person? Should be only one person to get the final out of the serial number plus m, because the person to report M-1 has been out, only 2 people, then the other is the final out of the row, using the formula "2", can be expressed as the following forms:
F(2) = [F(1) + M] % N = [F(1) + M] % 2
For example, n=2, m=3, has f (2) = [F (1) + m]%n = (0 + 3)%2 = 1
According to the derivation process above, it is easy to deduce the formula when n=3:
F(3) = [F(2) + M] % N = [F(2) + M] % 3
So we can get a recursive formula:
F(1) = 0F(N) = [F(N - 1) + M] % N (N>1)
With this recursive formula, you can use a recursive method to design a program:
#Include<iostream>UsingNamespaceStdint josephus (int N, int m) {if (1 = = N) {return 0;} return (Josephus (N-1, m) + m)% n;} int main () {int N, M; cin >> n >> m; cout << "the last person to dequeue is numbered (starting from 0):" << Josephus (n, m) << ENDL; return 0;}
Operation Result:
13 3最后出列的人的编号为(从0开始编号):12
Using recursive functions consumes more memory from your computer, which can cause programs to fail when the recursion level is too deep, such as the 64-storey tower that needs to be calculated for a long time.
Therefore, the program can be written directly to the following recursive form:
#include <iostream >using namespace std;int main () { int N, M; cin >> n >> m; int out = 0; for (int i = 2; i <= n; i++) {out = (o UT + m)% i; } cout << "the last person to dequeue is numbered (starting from 0):" << out << Span class= "hljs-built_in" >ENDL; return 0;}
Kids learn data structure (1): The chain list solution, array solution and mathematical formula solution of Joseph Ring