An outright understanding of backtracking algorithms

Source: Internet
Author: User

Defined

In the program design, there are quite a few problems, such as solving the problem of solving a group of solutions or finding the best solution, for example, the eight Queens question that the reader is familiar with, not according to a certain calculation rule, but using the heuristic and backtracking search technique. Backtracking is also an important method of design recursion, and its solution is essentially a process of first-order traversal of a "state tree", but the tree is not pre-built before traversal, but implicit in the traversal process.

---"data Structure" (Min)

How do you understand this passage?

First of all, the solution of a problem is difficult for us to find the rules to calculate, there is no formula to follow, can only list all possible solutions, and then each to check whether each solution conforms to the conditions we are looking for, that is, usually said traversal. And many of the solution space is tree-type, is the tree traversal.

Secondly, the first sequence traversal of the tree, that is, the root is checked first, the binary tree of the first order traversal is the root, the left subtree, the right sub-tree order is output. If you think of a tree as a special kind of diagram, DFS is the first order traversal. Therefore, backtracking and DFS are very closely related and can be thought of as a kind of application scenario of Dfs. In addition, DFS has a benefit, it only stores depth, not the breadth of storage. Therefore, the space complexity is small, and the time complexity is large.

Finally, some of the solution spaces are very large and can be thought of as a very large tree, at which time complexity of full traversal is intolerable. At this point, you can check some conditions at the same time, when traversing a branch, if the condition is not satisfied, then back to the root node into the next branch of the traversal. This is the source of the word "backtracking". The selected traversal according to the condition is called pruning or branching and delimitation.

Dfs

First look at DFS, the following is the introduction of the algorithm of DFS pseudo-code, it is worth a line of taste. It is necessary to pay attention to the process of dyeing, because the graph is likely to have a ring, so you need to record those nodes have been visited, those are not, and the tree traversal is no dyeing process. And it uses π[m] to record the parent node of M, and it can record the path of DFS.

DFS (G)
1 for each vertex u∈v [G]
2 Do Color[u]←white
3π[u]←nil
4 time←0
5 for each vertex u∈v [G]
6 do if color[u] = White
7 Then Dfs-visit (u)
Dfs-visit (U)
1 Color[u]←gray
2 Time←time +1
3 D[u] <-time
4 for each v∈adj[u]
5 do if color[v] = White
6 Thenπ[v]←u
7 Dfs-visit (v)
8 Color[u] <-black

Example

Example One : The problem of exponentiation is to return a subset of all the sets. Why is it called a power set? Because a collection has n elements, all of its subsets are 2^n. For example [],[1],[2],[3],[1,2],[1,3],[2,3],[1,2,3] is a subset of [A.

This is the leaf node of this tree:


The question becomes how to output the leaf node of a tree. Then you need to know exactly which layer you are traversing. There are many methods, which can be recorded with global variables, or with the parameters of recursive functions.

A) Here is the global variable record, when entering the function level++, exit the function when level--

int level=0;vector<vector<int> > result;vector<int> temp;void dfs (vector<int>& S) {    level++;    if (Level>s.size ()) {        result.push_back (temp);        level--;        return;    }    Temp.push_back (S[level-1]);    DFS (S);    Temp.pop_back ();    DFS (S);    level--;    return;} vector<vector<int> > Subsets (vector<int>& S) {    sort (s.begin (), S.end ());    DFS (S);    Reverse (Result.begin (), Result.end ());    return result;}

B) The number of layers used here is the function parameter

vector<vector<int> > Result;vector<int> temp;void dfs (vector<int>& S, int i) {    if (i== S.size ()) {        result.push_back (temp);        return;    }    Temp.push_back (S[i]);    DFS (s,i+1);    Temp.pop_back ();    DFS (s,i+1);    return;} vector<vector<int> > Subsets (vector<int>& S) {    dfs (s,0);    Reverse (Result.begin (), Result.end ());    return result;}

To summarize, the pseudo code is:

void Dfs (number of layers) {

if (condition) {

Output

}

else{

Treatment of Zuozi;

DFS (number of floors +1);

The treatment of the right sub-tree;

DFS (number of floors +1);

}

}

Example two: Queen's question, such as 8*8 's chessboard, how many queens can be placed? Chess rules, Queens in the same row, the same column, the same slash can attack each other.

The pseudo code is as follows:

int a[n];
void try (int i)
{
if (i==n) {
Output results;
}
Else
{
for (j = Nether; J <= Upper bound; j=j+1)//enumeration I all possible paths
{
if (Fun (j))//satisfies the limit function and the constraint condition
{
A[i] = 1;
...//Other operations
Try (i+1);
A[J] = 0;
}
}
}
}

According to the pseudo-code, write the most critical piece of code as follows. Where vector<vector<int> > M is a global variable that is used to record the Traverse path, set the value before traversing, and remove it after traversal. Every time the output is transferred, all functions that are pressed into the stack will be transferred to M[level][i]=0;

void Dfs (int level) {      if (level==n) {          output ();      }      else{for          (int i=0;i<n;i++) {              if (check (level+1,i+1)) {                  m[level][i]=1;                  DFS (level+1);                  m[level][i]=0;}}}}    

Full code:

int N;  Vector<vector<int> > m;  vector<vector<string> > result;              BOOL Check (int row,int column) {if (row==1) return true;              int i,j;              for (i=0;i<=row-2;i++) {if (m[i][column-1]==1) return false;              } i = Row-2;              j = i (Row-column);                  while (i>=0&&j>=0) {if (m[i][j]==1) return false;                  i--;              j--;              } i = Row-2;              j = row+column-i-2;                  while (i>=0&&j<=n-1) {if (m[i][j]==1) return false;                  i--;              j + +;          } return true;      } void Output () {vector<string> VEC;          for (int i=0;i<n;i++) {string S;              for (int j=0;j<n;j++) {if (m[i][j]==1) s.push_back (' Q ');          else S.push_back ('. ');} vec.push_back (s);  } result.push_back (VEC);      } void Dfs (int level) {if (level==n) {output ();                  } else{for (int i=0;i<n;i++) {if (check (level+1,i+1)) {m[level][i]=1;                  DFS (LEVEL+1);              m[level][i]=0;      }}}} vector<vector<string> > Solvenqueens (int n) {n=n;          for (int i=0;i<n;i++) {vector<int> A (n,0);      M.push_back (a);      } dfs (0);  return result; }

Example Three:The problem of Sudoku is to give a sudoku to solve it.

For example, give the following:


Solving:


The solution space is this:


Since Sudoku is 9*9, there are 81 layers of solution space, each of which has 9 branches, and what we do is to traverse this solution space.

If we only ask for a solution, we can return it after we get the solution, and whether the tag gets a solution can be done with a global variable or a return value,

With global variables, the code is as follows:

BOOL flag= false;bool Check (int k, vector<vector<char> > &board) {int x=k/9;        int y=k%9;        for (int i = 0; i < 9; i++) if (i! = x && board[i][y] = = Board[x][y]) return false; for (int j = 0; J < 9; J + +) if (j! = y && board[x][j] = = Board[x][y]) return F        Alse;                for (int i = 3 * (X/3), I < 3 * (X/3 + 1); i++) for (int j = 3 * (Y/3); J < 3 * (Y/3 + 1); J + +)        if (i! = x && J! = y && board[i][j] = = Board[x][y]) return false;    return true;        }void dfs (int num,vector<vector<char> > &board) {if (num==81) {flag=true;    Return        } else{int X=NUM/9;        int y=num%9; if (board[x][y]== '. ')                {for (int i=1;i<=9;i++) {board[x][y]=i+ ' 0 ';                  if (check (num,board)) {DFS (num+1,board);  if (flag) return;        }} board[x][y]= '. ';        } else{dfs (Num+1,board); }}}void Solvesudoku (vector<vector<char> > &board) {dfs (0,board);}
With the return value, the key part can be modified:

BOOL F (int i, vector<vector<char> > &board) {        if (i==n*m)            return true;        if (board[i/n][i%m]== '. ') {for            (int k=1;k<=9;k++) {                board[i/n][i%m]=k+ ' 0 ';                    if (check (I,board) && F (i+1,board))                            return true;            Board[i/n][i%m]= '. ';            return false;        }        else            return F (i+1,board);    }

If all solutions are required, they can be saved when the solution is present:

vector<vector<vector<char> >> sum;bool Check (int k, vector<vector<char> > &board) {        int X=K/9;        int y=k%9;        for (int i = 0; i < 9; i++) if (i! = x && board[i][y] = = Board[x][y]) return false; for (int j = 0; J < 9; J + +) if (j! = y && board[x][j] = = Board[x][y]) return F        Alse;                for (int i = 3 * (X/3), I < 3 * (X/3 + 1); i++) for (int j = 3 * (Y/3); J < 3 * (Y/3 + 1); J + +)        if (i! = x && J! = y && board[i][j] = = Board[x][y]) return false;    return true;        }void dfs (int num,vector<vector<char> > &board) {if (num==81) {sum.push_back (board);    Return        } else{int X=NUM/9;        int y=num%9; if (board[x][y]== '. ')                {for (int i=1;i<=9;i++) {board[x][y]=i+ ' 0 ';         if (check (Num,board)) {           DFS (Num+1,board);                if (flag)//return;        }} board[x][y]= '. ';        } else{dfs (Num+1,board); }}}void Solvesudoku (vector<vector<char> > &board) {dfs (0,board);} int main () {vector<string> Myboard ({"... 748 ... "," 7 ... ",". 2.1.9 ... ",". ". 7...24. ",". 64.1.59. ",". 98...3 ... "," ... 8.3.2. "," ... 6 "," ...    2759.. "});    Vector<char> Temp (9, '. ');    vector<vector<char> > Board (9,temp); for (int i=0;i<myboard.size (), i++) {for (int j=0;j<myboard[i].length (); j + +) {board[i][j]=myboard[i][        J];    }} solvesudoku (board);            for (int k=0;k<sum.size (), k++) {for (int i=0;i<sum[k].size (), i++) {for (int j=0;j<sum[k][i].size (); j + +) {        cout<<sum[k][i][j]<< "";    } cout<<endl;    } cout<< "######" <<endl; } cout<< "Sum is" <<sum.size () <<endl;    cout << "Hello world!" << Endl; return 0;}

In the end, we got 8 solutions.

There is an image on the wiki that expresses the process of backtracking:



An outright understanding of backtracking algorithms

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.