The Backtracking Method (exploration and backtracking) is an optimization search method that searches forward based on the optimization conditions to achieve the goal. However, when you find that the previous selection is not optimal or fails to reach the target, you can return to the previous step and re-select the target. This technology will return to the backtracing method if you fail to get the target, vertices that meet backtracing conditions are called backtracing points ".
Iteration and Recursion are the most prone to errors in programming. Tracing is the combination of the two methods. According to my understanding, the use of backtracking requires a structure in mind. The word tracing uses a very good image. According to human understanding, tracing is a relative concept in computer algorithms. If we do not move forward, we will go back. The outermost layer is an iteration loop, representing the previous step. The code in the iteration has a forward recursion. If the forward process does not meet the corresponding constraint function, then we continue the previous iteration process, which is called backtracking. Next, let's take a look at the core idea of the algorithm based on examples. This is my own code, so the quality may not be very high in some places.
In the following code, I define the constraint function as Place, and the name of the Backtracking function can be defined at will. Observe the structure of the Backtracking function.
N queen's question:
Place n queens that are not under attack on the chessboard of n × n grids. According to the rules of chess, the queen can attack pawns in the same row, column, or diagonal line. The problem after n is equivalent to placing n queens on the n × n board. Any two queens may wish to be on the same row, column, or diagonal line.
// N-Quene
Bool Place (int k, int I, int * x ){
For (int j = 0; j <k; j ++) {// decide wether the current queen conflict with other before queens
If (x [j] = I | abs (x [j]-I) = abs (j-k ))
Return false;
Return true;
}
}
Void NQueens (int k, int n, int * x ){
For (int I = 0; I <n; I ++ ){
If (Place (k, I, x )){
X [k] = I;
If (k = N-1 ){
For (int I = 0; I <n; I ++) cout <I <"";
Cout <endl;
} Else
NQueens (k + 1, n, x );
}
}
}
Void NQueens (int n, int * x ){
NQueens (0, n, x );
}
Int main (){
Int n;
Do {
Cout <"Enter the size of n: (n is not less than 3)" <endl;
Cin> n;
} While (n <3 );
Int * x = (int *) malloc (sizeof (int) * n );
NQueens (n, x );
}
The purpose of the constraint function is not to let the Queen k conflict with the former queen, so the constraint function here is very easy to write. Pay attention to backtracking functions. The for loop at the outermost layer tries this queen on all possible columns. If it can be put, it moves forward recursively. Once recursion is exited and N-1 is not reached, it is said that there is a place in front of it that cannot go through and continue the for loop, so that we can visually display what Backtracking is.
Next let's look at an instance problem:
Given the number of n, from 1-n, each number takes two rows into 2n. Sort the 2n numbers so that there is one number between 1 and n between... n. Lists all possible sorting results.
This question can be answered in a similar way.
# Include <stdio. h>
# Include <iostream>
Using namespace std;
// Constraint function
Bool Place (int k, int I, int * x) {// to see whether the selected index I is valid
If (x [I]! = 0 | x [I + k + 1]! = 0)
Return false;
Return true;
}
Void refresh (int k, int n, int * x ){
For (int j = 0; j <2 * n; j ++ ){
If (x [j] <= k)
X [j] = 0;
}
}
// Backtrack function
Void Backtrack (int k, int n, int * x ){
For (int I = 0; I <2 * n-k-1; I ++ ){
Refresh (k, n, x );
If (Place (k, I, x )){
X [I] = x [I + k + 1] = k;
If (k = 1) {// get the answer state
Cout <"=============================" <endl;
For (int j = 0; j <2 * n; j ++ ){
If (j = 2 * N-1)
Cout <x [j] <endl;
Else
Cout <x [j] <"\ t ";
}
} Else {
Backtrack (K-1, n, x );
}
}
}
}
Int main (){
Int n;
Do {
Cout <"Enter the size of n: (n is not less than 3)" <endl;
Cin> n;
} While (n <3 );
Cout <"the sorting result is as follows:" <endl;
Int * x = (int *) malloc (sizeof (int) * n * 2); // define the array
// Int * x = new int [n];
For (int I = 0; I <n * 2; I ++) // initialize the array
X [I] = 0;
Backtrack (n, n, x );
Char;
Cin>;
Return 0;
}
Here, my constraint function is relatively simple to write, but under the for loop, the refresh function must be added to restore the array state, otherwise the algorithm will not be able to do so, because my constraint function is determined based on the status of the array.
Backtracking is used in many cases, so we need to understand and use it flexibly.