⌛ The origin of Joseph's problem: [finally, we will test it to see if it is correct]
it is said that Joseph, a famous Jewish historian, once had the following story: after the Romans occupied jotapat, 39 Jews hid in a cave with Joseph and his friends. 39 Jews decided that they would rather die than be caught by the enemy, so they decided to commit suicide. 41 people lined up in a circle and the first one began to count off, Every time the third person reports, the person must commit suicide, and then report again from the next one until all people commit suicide. However, Joseph and his friends did not want to comply. Where do you have to stand in the first place to avoid execution? The clever Joseph arranged his friends and himself in the 16th and 31st positions, so he escaped the death game.
Joseph ☁️
Link to previous question: Punch in C/C + + 100 questions [2 / 100] - stupid monkey taking CET-4 and CET-6 ⭐ ️ ⭐ Query string.
General contents of 100 punch outs: 🚧 🚧 …
1, Title Overview
● n n n people form a circle, and their numbers are respectively at the beginning 1 , 2 , . . . , n 1,2,...,n 1,2,...,n. Start counting from the first person and count to m m m people out of the line, and then the next person from 1 1 1 start counting, count to m m m's people will circle again, and so on, until all people are out of the circle. Please output the number of people who circle in turn.
● input Description:
Enter two integers
n
,
m
n,m
n,m.
● output Description:
Output one line
n
n
n integers, output the number of each person in turn.
note: among them, 1 ≤ m , n ≤ 100 1≤m,n≤100 1≤m,n≤100. Operation limit - > maximum operation time: 1 s 1s 1s, maximum running memory: 128 M 128M 128M
● input example:
10 3
● output example:
3 6 9 2 7 1 8 5 10 4
2, Thinking blank
● topic difficulty: ⭐ ️ ⭐ ️ ⭐ ️
● suggested thinking time: ⌛ ️ ⌛ ️
3, Topic analysis
● this is a question to check the linked list. You can use arrays or linked lists. Here, consider using linked lists. (mainly the knowledge points that can review the linked list)
- First, let's briefly review the knowledge of linked lists:
① Linked list is a non continuous and non sequential storage structure on the physical storage unit. The logical order of data elements is realized through the pointer link order in the linked list.
② The linked list consists of a series of nodes (each element in the linked list is called a node), which can be generated dynamically at run time.
③ Each node consists of two parts: one is the data field that stores the data element, and the other is the pointer field that stores the address of the next node.
● simple example of single linked list structure:
● simple example of bidirectional linked list structure:
● note: it should be noted here that the pointers are not all "int *, double *, float *", that is to say, "the pointer is not the one with * sign". But that is: as long as the variable that can indicate a certain data is a "pointer" (generalized pointer).
● algorithm design:
[1] Design the input and output module.
[2] Design the structure of "human".
[3] Two sub branches are designed under the counting module:
< 1 > the number reported by the teller is just the number reported“
m
m
m "
< 2 > the number of persons who did not report“
m
m
m "
Step [1]: I / O module
● it's easy:
#include <stdio.h> int main() { /* Input module */ int n, m; int ans[110]; // ans []: an array that stores answers. The open array space can be greater than 100 scanf("%d%d", &n, &m); /* Algorithm design */ ... while (...) // Reporting cycle { ... } /* output module */ for (int i = 1; i <= n; i++) printf("%d ", ans[i]); printf("\n"); return 0; }
Step [2]: structure of "human"
● when these people form a circle, they naturally have three attributes:
① he had his own number at the beginning.
② the number of the person on his left.
③ the number of the person on his right.
typedef struct List_Node // typedef: alias the following "Node" { int own_number; // Own number int left_ind; // The number of the person on the left int right_ind; // The number of the person on the right }Node;
● after designing the structure of "people", connect them (i.e. perform initialization operation, i.e. form a circle).
#include <stdio.h> typedef struct List_Node // typedef: alias the following "Node" { int own_number; // Own number int left_ind; // The number of the person on the left int right_ind; // The number of the person on the right }Node; int main() { /* Input module */ ... /* Structure initialization module */ Node a[110]; for (int i = 1; i <= n; i++) { a[i].own_number = i; // I know my number a[i].left_ind= i - 1; // I will also know the number of the person on my left a[i].right_ind= i + 1; // I will also know the number of the person on my right } a[1].left_ind= n; // Remember to assign the number of the nth person to the left side of the first person a[n].right_ind= 1; // Because they form a circle /* Algorithm design */ ... while (...) // Reporting cycle { ... } /* output module */ ... return 0; }
● we can simply check whether our structure is successfully constructed through the following code:
for (int i = 1; i <= n; i++) printf("%d <-- [On my left is],[My number is: %d ],[On my right is]--> %d\n", a[i].front_ind, a[i].own_number, a[i].next_ind);
● operation results: [it can be seen that 10 of them have successfully "encircled" into a circle]
Step [3]: counting module
● after we have designed the structure, they are connected through "an invisible chain". At the beginning of counting, we need a pointer to point to the first person.
● the frame of data reporting module is as follows:
#include <stdio.h> typedef struct List_Node // typedef: alias the following "Node" { ... }Node; int main() { /* Input module */ ... /* Structure initialization module */ ... /* Counting module */ int ans[110]; // Record the number of people who circle in turn int ans_i = 1; // Dynamic subscript when saving answer int fp = 1; // The pointer, at the beginning, points to the first person int cnt = 1; // Counter, every time m is checked in, the person pointed by fp will go out of the circle while ( ans_i <= n ) // Bad news cycle, { if ( cnt == m ) // The teller just checked in "m" { ... ans[ans_i++] = a[fp].own_number; // Answer assignment ... } else // The teller did not check in "m" { ... } } /* output module */ ... return 0; }
<1> The teller just checked in the number "m"
● when someone needs to go out, for example, when he counts off on the first lap, the m-th person needs to go out of the lap. After he goes out of the lap, the person on his left will no longer be him on the right; and the person on his right will no longer be him on the left. Therefore, after he goes out of the lap, we have to carry out subsequent processing, that is, update the linked list.
● for the small mechanism of "updating linked list", I also made a visual diagram as follows for easy understanding:
● finally, the pointer points to the right_ind of the "person out of the circle" (i.e. the number of his current right-hand person). The code is as follows:
/* Counting module */ int ans[110]; // Record the number of people who circle in turn int ans_i = 1; // Dynamic subscript when saving answer int fp = 1; // The pointer, at the beginning, points to the first person int cnt = 1; // Counter, every time m is checked in, the person pointed by fp will go out of the circle while ( ans_i <= n ) // Reporting cycle { if ( cnt == m ) // The teller just checked in "m" { /* Update linked list */ int left = a[fp].left_ind; // Get the number of the person on the left int right = a[fp].right_ind; // Get the number of the person on the right a[left].right_ind = a[right].own_number; // See the legend above for easy understanding a[right].left_ind = a[left].own_number; // See the legend above for easy understanding /* Answer saving + subsequent processing */ cnt = 1; // The counter returns to 1 ans[ans_i++] = a[fp].own_number; // Answer assignment fp = a[fp].right_ind; // fp points to the next person } else // The teller did not check in "m" { ... } }
<2> The number "m" that the teller failed to report
● when he doesn't need to go out, just let the pointer point to his right_ind (i.e. the number of the person on his current right).
/* Counting module */ int ans[110]; // Record the number of people who circle in turn int ans_i = 1; // Dynamic subscript when saving answer int fp = 1; // The pointer, at the beginning, points to the first person int cnt = 1; // Counter, every time m is checked in, the person pointed by fp will go out of the circle while ( ans_i <= n ) // Bad news cycle, { if ( cnt == m ) // The teller just checked in "m" { ... } else // The teller did not check in "m" { cnt++; // Count off + 1 fp = a[fp].right_ind; // fp points to the next person } }
● so far, we have solved the problem. Test the historical story at the beginning of the article:
● Joseph cow!
4, Summary and reflection
● in fact, you can use a one-way list instead of a "two-way linked list", but you need to set an additional pointer (for pointing to the previous person of fp).
● combine the knowledge of linked list (data structure) and structure to solve the problem.
5, Complete code (C and C + +)
● C language version:
#include<stdio.h> typedef struct List_Node { int own_number; // Own number int left_ind; // The number of the person on the left int right_ind; // The number of the person on the right }Node; int main() { /* Input module */ int n, m; scanf("%d%d", &n, &m); /* Initialization module */ Node a[110]; // ans []: an array that stores answers. The open array space is greater than 100 for (int i = 1; i <= n; i++) { a[i].own_number = i; // I know my number a[i].left_ind = i - 1; // I will also know the number of the person on my left a[i].right_ind = i + 1; // I will also know the number of the person on my right } a[1].left_ind = n; // Remember to assign the number of the nth person to the left side of the first person a[n].right_ind = 1; // Because they form a circle /* Counting module */ int ans[110]; // Record the number of people who circle in turn int ans_i = 1; // Dynamic subscript when saving answer int fp = 1; // The pointer, at the beginning, points to the first person int cnt = 1; // Counter, every time m is checked in, the person pointed by fp will go out of the circle while (ans_i <= n) { if (cnt == m) // The teller just checked in "m" { /* Update linked list */ int left = a[fp].left_ind; // Get the number of the person on the left int right = a[fp].right_ind; // Get the number of the person on the right a[left].right_ind = a[right].own_number; // See the following legend for easy understanding a[right].left_ind = a[left].own_number; // See the following legend for easy understanding /* Answer saving + subsequent processing */ cnt = 1; // The counter returns to 1 ans[ans_i++] = a[fp].own_number; // Answer assignment fp = a[fp].right_ind; // fp points to the next person } else // The teller did not check in "m" { cnt++; // Count off + 1 fp = a[fp].right_ind; // fp points to the next person } } /* output module */ for (int i = 1; i <= n; i++) printf("%d ", ans[i]); return 0; }
● operation results:
● C + + version:
#include<iostream> using namespace std; typedef class List_Node // typedef: alias the following "Node" { public: int own_number; // Own number int left_ind; // The number of the person on the left int right_ind; // The number of the person on the right }Node; int main() { /* Input module */ int n, m; cin >> n >> m; /* Initialization module */ Node a[110]; // ans []: an array that stores answers. The open array space is greater than 100 for (int i = 1; i <= n; i++) { a[i].own_number = i; // I know my number a[i].left_ind = i - 1; // I will also know the number of the person on my left a[i].right_ind = i + 1; // I will also know the number of the person on my right } a[1].left_ind = n; // Remember to assign the number of the nth person to the left side of the first person a[n].right_ind = 1; // Because they form a circle /* Counting module */ int ans[110]; // Record the number of people who circle in turn int ans_i = 1; // Dynamic subscript when saving answer int fp = 1; // The pointer, at the beginning, points to the first person int cnt = 1; // Counter, every time m is checked in, the person pointed by fp will go out of the circle while (ans_i <= n) { if (cnt == m) // The teller just checked in "m" { /* Update linked list */ int left = a[fp].left_ind; // Get the number of the person on the left int right = a[fp].right_ind; // Get the number of the person on the right a[left].right_ind = a[right].own_number; // See the following legend for easy understanding a[right].left_ind = a[left].own_number; // See the following legend for easy understanding /* Answer saving + subsequent processing */ cnt = 1; // The counter returns to 1 ans[ans_i++] = a[fp].own_number; // Answer assignment fp = a[fp].right_ind; // fp points to the next person } else // The teller did not check in "m" { cnt++; // Count off + 1 fp = a[fp].right_ind; // fp points to the next person } } /* output module */ for (int i = 1; i <= n; i++) cout << ans[i] << " "; return 0; }
6, Refer to Appendix
[1] Original address: https://www.luogu.com.cn/problem/P1996.
Link to previous question: Punch in C/C + + 100 questions [2 / 100] - stupid monkey taking CET-4 and CET-6 ⭐ ️ ⭐ Query string.
General contents of 100 punch outs: 🚧 🚧 …
C/C + + 100 questions punch in [3 / 100] - Joseph's question [the title comes from Luogu] ⭐ ️ ⭐ ️
Tags: analog, array, linked list
Because there are important exams recently, it's a week off
2021/12/5