1. Generate an arrangement of 1 ~ n
Ideas
Try to use recursive thinking to solve the problem: first output all the permutations starting with 1 (this step is a recursive call), then output the permutations starting with 2 (also a recursive call), then the permutations starting with 3… and finally the permutations starting with 3.
n
n
Mine starting with n.
The characteristics of the arrangement starting with 1: the first one is 1, followed by the arrangement of 2 ~ 9. According to the definition of lexicographic order, these arrangements of 2 ~ 9 must also be arranged in lexicographic order. In other words, it is necessary to “output the permutations 2 ~ 9 in dictionary order”, but it should be noted that when outputting, “1” must be added at the beginning of each permutation. As a result, the designed recursive function requires the following parameters:
- The “prefix” sequence that has been determined for output.
- A collection of elements that need to be fully arranged so that the first element can be selected in sequence.
pseudocode:
void print_permutation(sequence A, set S) {<!-- --> if (S is empty) output sequence A; else consider each element v of S in order from small to large {<!-- --> print_permutation(get a new sequence after adding v at the end of A, S-{<!-- -->v}); } }
It is not difficult to think of using an array to represent the sequence A, and the set S does not need to be saved at all, because it can be completely determined by the sequence A – the elements that do not appear in A are optional. Functions in the C language cannot determine the number of elements in the array when accepting array parameters, so they need to pass a number of positions that have been filled in, or the current element position that needs to be determined cur
.
Code
/********************************************** *************************** > File Name: Generate an arrangement of 1~n.cpp > Author: Maureen > Mail: [email protected] > Created Time: Friday 10/27 19:21:28 2023 *************************************************** ************************/ #include <iostream> using namespace std; int A[101]; void print_permutation(int n, int *A, int cur) {<!-- --> if (cur == n) {<!-- --> //Recursion boundary for (int i = 0; i < n; i + + ) {<!-- --> printf("%d ", A[i]); } printf("\\ "); } else {<!-- --> for (int i = 1; i <= n; i + + ) {<!-- --> //Try to fill in various integers i in A[cur] bool ok = true; //Check if i has been used for (int j = 0; j < cur; j + + ) {<!-- --> if (A[j] == i) {<!-- --> ok = false; //If i has already appeared in A[0]~A[cur-1], it cannot be selected again } } if (ok) {<!-- --> A[cur] = i; print_permutation(n, A, cur + 1); //recursive call } } } } int main() {<!-- --> int n; scanf("%d", & amp;n); print_permutation(n, A, 0); return 0; }
2. Resettable full permutation (recursive)
Modify the problem to: input an array P, and output all permutations of each element of the array P in lexicographic order.
Just add P to the parameter list of print_permutation
and change if(A[j] == i)
to if (A[j] == P[i])
, A[cur] = i
is modified to A[cur] = P[i]
. In this way, just sort all the elements of P from small to large, and then call print_permutation(n, P, A, 0)
.
The method is good, but there is a small problem: after entering 1 1 1
, the program has no output. The reason is that the program prohibits duplication in the A array, and when there are duplicate elements in P, the Array limits are just wrong.
One solution is to count the number of occurrences c1 of P[i] in A[0] ~ A[cur – 1], and the number of occurrences c2 of P[i] in the P array. As long as c1 < c2, it can be called recursively.
else {<!-- --> for (int i = 0; i < n; i + + ) {<!-- --> int c1 = 0, c2 = 0; for (int j = 0; j < cur; j + + ) {<!-- --> if (A[j] == P[i]) c1 + + ; } \t\t for (int j = 0; j < n; j + + ) {<!-- --> if (P[j] == P[i]) {<!-- --> c2++; } } \t\t if (c1 < c2) {<!-- --> A[cur] = P[i]; print_permutation(n, P, A, cur + 1); } } }
Enter 1 1 1
, and 27 1 1 1 are output. There are no omissions, but there are duplications: first try to use the first 1 as the beginning, after the recursive call is completed, try to use the second 1 as the beginning, after the recursive call is completed, try to use the third 1 as the beginning, and call again recursively . But in fact these three 1’s are the same and should only be recursed once, not three times.
In other words, the enumeration subscript i
should take all P[i] values without duplication or omission. Since the P array is already sorted, we only need to check the first element of P and all elements that are not the same as the previous element.
Code
/********************************************** *************************** > File Name: Resettable full arrangement.cpp > Author: Maureen > Mail: [email protected] > Created Time: Friday 10/27 19:42:25 2023 *************************************************** ************************/ #include <cstdio> #include <algorithm> using namespace std; int P[101]; int A[101]; // Output the full arrangement of elements in array P. There may be duplicate elements in array P void print_permutation(int n, int *P, int *A, int cur) {<!-- --> if (cur == n) {<!-- --> for (int i = 0; i < n; i + + ) {<!-- --> printf("%d ", A[i]); } printf("\\ "); } else {<!-- --> for (int i = 0; i < n; i + + ) {<!-- --> if (!i || P[i] != P[i - 1]) {<!-- --> int c1 = 0, c2 = 0; for (int j = 0; j < cur; j + + ) {<!-- --> if (A[j] == P[i]) c1 + + ; } for (int j = 0; j < n; j + + ) {<!-- --> if (P[j] == P[i]) c2 + + ; } if (c1 < c2) {<!-- --> A[cur] = P[i]; print_permutation(n, P, A, cur + 1); } } } } } int main() {<!-- --> int n; while (scanf("%d", & amp;n) == 1 & amp; & amp; n) {<!-- --> for (int i = 0; i < n; i + + ) scanf("%d", & amp;P[i]); sort(P, P + n); print_permutation(n, P, A, 0); } return 0; }
3. Resettable full permutation (next_permutation)
Another way to enumerate all permutations is to start from the lexicographically smallest permutation and keep calling the “find next permutation” process. A library function next_permutation
is provided in C++’s STL.
Code
#include<cstdio> #include<algorithm> using namespace std; int main() {<!-- --> int n, p[10]; scanf("%d", & amp;n); for(int i = 0; i < n; i + + ) scanf("%d", & amp;p[i]); \t sort(p, p + n); // Sort to get the minimum arrangement of p do {<!-- --> for(int i = 0; i < n; i + + ) printf("%d ", p[i]); // Output arrangement p printf("\\ "); } while(next_permutation(p, p + n)); // Find the next permutation return 0; }
This code also works for resettable.
4. Summary
There are two common methods of enumeration permutation: one is recursive enumeration, and the other is using next_permutation
in STL.