Two way wide search: the so-called two-way search refers to the simultaneous search in two directions: forward search: search from the initial node to the target node; Reverse search: search from the target node to the initial node; When the search in two directions generates the same child node, the search process is terminated.
There are usually two implementation methods:
1. A queue is used to store the sub states. The starting point and end point join the queue successively, the forward search and reverse search are carried out alternately, and the search in the two directions is extended alternately. Until the search in both directions produces the same sub state.
2. Although the search in the two directions is alternately extended sub state. However, the speed of sub states generated in both directions is not necessarily balanced. Therefore, you can select the direction with a small number of sub states to expand first. In this way, there will be no imbalance in the speed of generator states in two directions, which can significantly improve the efficiency.
The two-way wide search template is given below
void TBFS() { bool found=false; memset(visited,0,sizeof(visited)); // Judgment array while(!Q1.empty()) Q1.pop(); // Forward queue while(!Q2.empty()) Q2.pop(); // Reverse queue //======The status of forward extension is marked as 1 and reverse extension is marked as 2 visited[s1.state]=1; // The initial status is marked as 1 visited[s2.state]=2; // The end status is marked as 2 Q1.push(s1); // Initial state into forward queue Q2.push(s2); // End status into reverse queue while(!Q1.empty() || !Q2.empty()) { if(!Q1.empty()) BFS_expand(Q1,true); // Search in forward queue if(found) // End of search return ; if(!Q2.empty()) BFS_expand(Q2,false); // Search in reverse queue if(found) // End of search return ; } } void BFS_expand(queue<Status> &Q,bool flag) { s=Q.front(); // Get the header node s from the queue Q.pop() for( each s Child nodes of t ) { t.state=Gethash(t.temp) // Get the status of child nodes if(flag) // Judge in forward queue { if (visited[t.state]!=1)// Not in the forward queue { if(visited[t.state]==2) // This state has occurred in the reverse queue { Various operations; found=true; return; } visited[t.state]=1; // Mark as in forward queue Q.push(t); // Join the team } } else // Judge in forward queue { if (visited[t.state]!=2) // Not in the reverse queue { if(visited[t.state]==1) // This state has occurred in the forward queue { Various operations; found=true; return; } visited[t.state]=2; // Mark as in reverse queue Q.push(t); // Join the team } } }
Here is the eight digit problem
C - Eight
The 15-puzzle has been around for over 100 years; even if you don't know it by that name, you've seen it. It is constructed with 15 sliding tiles, each with a number from 1 to 15 on it, and all packed into a 4 by 4 frame with one tile missing. Let's call the missing tile 'x'; the object of the puzzle is to arrange the tiles so that they are ordered as:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 x
where the only legal operation is to exchange 'x' with one of the tiles with which it shares an edge. As an example, the following sequence of moves solves a slightly scrambled puzzle:
1 2 3 4 1 2 3 4 1 2 3 4 1 2 3 4 5 6 7 8 5 6 7 8 5 6 7 8 5 6 7 8 9 x 10 12 9 10 x 12 9 10 11 12 9 10 11 12 13 14 11 15 13 14 11 15 13 14 x 15 13 14 15 x r-> d-> r->
The letters in the previous row indicate which neighbor of the 'x' tile is swapped with the 'x' tile at each step; legal values are 'r','l','u' and 'd', for right, left, up, and down, respectively.
Not all puzzles can be solved; in 1870, a man named Sam Loyd was famous for distributing an unsolvable version of the puzzle, and
frustrating many people. In fact, all you have to do to make a regular puzzle into an unsolvable one is to swap two tiles (not counting the missing 'x' tile, of course).
In this problem, you will write a program for solving the less well-known 8-puzzle, composed of tiles on a three by three
arrangement.
Input
You will receive a description of a configuration of the 8 puzzle. The description is just a list of the tiles in their initial positions, with the rows listed from top to bottom, and the tiles listed from left to right within a row, where the tiles are represented by numbers 1 to 8, plus 'x'. For example, this puzzle
1 2 3 x 4 6 7 5 8
is described by this list:
1 2 3 x 4 6 7 5 8
Output
You will print to standard output either the word ``unsolvable'', if the puzzle has no solution, or a string consisting entirely of the letters 'r', 'l', 'u' and 'd' that describes a series of moves that produce a solution. The string should include no spaces and start at the beginning of the line.
Sample Input
2 3 4 1 5 x 7 6 8
Sample Output
ullddrurdllurdruldr
The eight digit problem is also known as the nine palace problem. In 3 × There are eight pieces on the chessboard of 3. Each piece is marked with a number from 1 to 8. The numbers marked on different pieces are different. There is also a space on the chessboard. The pieces adjacent to the space can be moved into the space. The problem to be solved is to give an initial state and a target state, and find a moving step with the least number of moving chess steps from the initial state to the target state.
Here is the code for two-way wide search to solve the eight digit problem
#include<iostream> #include<cstdio> #include<cstring> #include<algorithm> #include<cmath> #include<cstdlib> #include<vector> #include<queue> using namespace std; #define N 10 #define MAX 365000 char visited[MAX]; int father1[MAX]; // Save the parent node in the current state of forward search int father2[MAX]; // Save the parent state node in the current state of reverse search int move1[MAX]; // Save in forward search direction int move2[MAX]; // Save in reverse search direction struct Status // structure { char eight[N]; // Eight digit status int space; // x position int state; // hash value, used for status saving and duplicate judgment }; queue<Status> Q1; // Forward queue queue<Status> Q2; // Reverse queue Status s,s1,s2,t; bool found; // Search success flag int state; // Intersection state of positive and negative search int factory[]={1,1,2,6,24,120,720,5040,40320,362880}; // 0 n factorial int dir[4][2]={{-1,0},{1,0},{0,-1},{0,1}}; int Gethash(char eight[]) // Cantor expansion (get status, used for weight judgment) { int k=0; for(int i=0;i<9;i++) { int t=0; for(int j=i+1;j<9;j++) if(eight[j]<eight[i]) t++; k+=(t*factory[9-i-1]); } return k; } int ReverseOrder(char eight[]) // Find the reverse order number of States { int i,j,num=0; for(i=0;i<9;i++) { for(j=0;j<i;j++) { if(int(eight[i])==9) { break; } if(int(eight[j])==9) continue; if(int(eight[j])>int(eight[i])) num++; } } num=num%2; return num; } void BFS_expand(queue<Status> &Q,bool flag) // One way breadth search { int k,x,y; s=Q.front(); Q.pop(); k=s.space; x=k/3; y=k%3; for(int i=0;i<4;i++) { int xx=x+dir[i][0]; int yy=y+dir[i][1]; if(xx>=0 && xx<=2 && yy>=0 && yy<=2) { t=s; t.space=xx*3+yy; // Calculate x position swap(t.eight[k],t.eight[t.space]); // Swap two number positions t.state=Gethash(t.eight); if(flag) // Judge in forward queue { if(visited[t.state]!=1 && ReverseOrder(t.eight)==0) // It does not appear in the forward queue and satisfies parity { move1[t.state]=i; // Saves the direction of the forward search father1[t.state]=s.state; // Save the parent node in the current state of forward search if(visited[t.state]==2) // The current state has appeared in the reverse queue { state=t.state; // Save collision status (and intersection points) in positive and negative search found=true; // Search succeeded return; } visited[t.state]=1; // Mark as in forward queue Q.push(t); // Join the team } } else // Judge in reverse queue { if(visited[t.state]!=2 && ReverseOrder(t.eight)==0) // It does not appear in the reverse queue and satisfies parity { move2[t.state]=i; // Saves the direction of the reverse search father2[t.state]=s.state; // Save the parent state node in the current state of reverse search if(visited[t.state]==1) // The current state has appeared in the forward queue { state=t.state; // Save collision status (and intersection points) in positive and negative search found=true; // Search succeeded return; } visited[t.state]=2; // Mark as in reverse queue Q.push(t); // Join the team } } } } return ; } void TBFS() // Bidirectional search { memset(visited,0,sizeof(visited)); while(!Q1.empty()) Q1.pop(); while(!Q2.empty()) Q2.pop(); visited[s1.state]=1; // Initial state father1[s1.state]=-1; visited[s2.state]=2; // Target status father2[s2.state]=-1; Q1.push(s1); Q2.push(s2); while(!Q1.empty() || !Q2.empty()) { if(!Q1.empty()) BFS_expand(Q1,true); if(found) return ; if(!Q2.empty()) BFS_expand(Q2,false); if(found) return ; } } void PrintPath1(int father[],int move[]) // Find the path from the intersection state to the initial state { int n,u; char path[1000]; n=1; path[0]=move[state]; u=father[state]; while(father[u]!=-1) { path[n]=move[u]; n++; u=father[u]; } for(int i=n-1;i>=0;--i) { if(path[i] == 0) printf("u"); else if(path[i] == 1) printf("d"); else if(path[i] == 2) printf("l"); else printf("r"); } } void PrintPath2(int father[],int move[]) // Find the path from the intersection state to the target state { int n,u; char path[1000]; n=1; path[0]=move[state]; u=father[state]; while(father[u]!=-1) { path[n]=move[u]; n++; u=father[u]; } for(int i=0;i<=n-1;i++) { if(path[i] == 0) printf("d"); else if(path[i] == 1) printf("u"); else if(path[i] == 2) printf("r"); else printf("l"); } } int main() { int i; char c; while(scanf(" %c",&c)!=EOF) { if(c=='x') { s1.eight[0]=9; s1.space=0; } else s1.eight[0]=c-'0'; for(i=1;i<9;i++) { scanf(" %c",&c); if(c=='x') { s1.eight[i]=9; s1.space=i; } else s1.eight[i]=c-'0'; } s1.state=Gethash(s1.eight); for(int i=0;i<9;i++) s2.eight[i]=i+1; s2.space=8; s2.state=Gethash(s2.eight); if(ReverseOrder(s1.eight)==1) { cout<<"unsolvable"<<endl; continue; } found=false; TBFS(); if(found) // Search succeeded { PrintPath1(father1,move1); PrintPath2(father2,move2); } else cout<<"unsolvable"<<endl; cout<<endl; } return 0; }