Use STL to implement DFS/BFS algorithms-push box games (2)
Source: Internet
Author: User
Use STL to implement DFS/BFS Algorithms-- Push box games(2)We have provided the input and output operators for sokostate. Next, let's take a look at the istarget () member function. It is very simple. Just check whether every box has been moved to the destination, that is, check the isdest () status of each grid and isbox () whether the status is the same (both true and false ). The Code is as follows: bool sokostate: istarget () const {for (INT I = 1; I <rows _-1; I ++) {for (Int J = 1; j <Cols _-1; j ++) {point P (I, j); If (isdest (p )! = Isbox (p) return false;} return true;} because the outer circle of a two-dimensional graph must be wall, no check is required, which can make us a little faster. Before entering the nextstep () member function, let's take a look at the sokostep class and its related functions. Two things are required to represent one step of movement: position and direction. So I define sokostep class: Class sokostate {... Struct sokostep // records the movement of the box in each step {int X _; int Y _; char D _; // direction: R, L, U, d sokostep (int x, int y, char D): X _ (x), Y _ (Y), D _ (d) {} friend ostream & operator <(ostream & OS, const sokostep & S) {OS <"[" <S. X _ <"," <S. Y _ <"," <S. D _ <"]"; return OS ;}};...} It has a constructor and an output operator, because after finding the answer, we will move every step of the output from the initial question status and answer status, this output operator can help a lot. To output the answer, we also need to add a printanswer () member function to the sokostate class, because the data members of the sokostate class are private. The task is to output the data member steps _. Steps _ is a vector container. We can use the copy algorithm and ostream_iterator adapter, as shown in the following figure: void sokostate: printanswer (ostream & OS) const {copy (Steps _. begin (), steps _. end (), ostream_iterator <sokostep> (OS, "");} below is our most important part: nextstep () member function. My idea is to scan all the boxes in the current status to determine which box can be moved in which direction, find all possible moves, and return them to DFS/BFs. With the processing of the stateeq () member function given above, it is very easy to judge whether a moving operation is possible: as long as one side of the box is empty and someone on the other side can move in the empty direction, otherwise the box cannot move (either one side has obstacles or the other side has no one ). According to this method, we write the movebox () member function for nextstep () to call, as shown below: bool sokostate: movebox (sokostate & R, point box, point Soko, point nbox, char d) const {If (! Issoko (Soko) |! Isspace (nbox) return false; r = * this; for (INT I = 0; I <R. rows _; I ++) // clear the Soko flag {for (Int J = 0; j <R. cols _; j ++) {R. map _ [I] [J] & = ~ Flagsoko ;}} R. Map _ [box. X _] [box. Y _] & = ~ Flagbox; // move the box R. map _ [box. X _] [box. Y _] | = flagsoko; R. map _ [nbox. X _] [nbox. Y _] | = flagbox; R. stateeq (); R. steps _. push_back (sokostep (box. X _, box. Y _, D); Return true;} movebox () has five parameters. The first parameter is a sokostate reference, which is used to return the status after moving (if it can be moved; parameters 2, 3, and 4 are respectively the position of the box, and the position of the box after moving. The last parameter is the moving direction, which is indicated by a char ('U', 'D ', 'l' and 'R' indicate the upper, lower, and lower sides respectively); the function returns a bool value to indicate whether it can be moved. The function was used to determine whether it could be moved from the very beginning. The method we mentioned earlier is to check whether there are people on one side of the box and whether there is space on the other side. If it can be moved, copy the current status to the target status variable returned, and modify the target status. The modification is divided into four steps: first, clear all Soko flags in the target State. This is because after the box is moved, some of the multiple Soko flags originally calculated using stateeq () will be invalid, the stateeq () must be re-used for calculation. Then, modify the flag in the cell that the box is moved to, including clearing the box flag of the original box and setting it to The Soko flag, and set the box's new cell to the box sign. The third step is to call stateeq () to recalculate the Soko sign of the entire two-dimensional graph; finally, add the move step to the steps _ member. In this way, true is returned. The nextstep () member function finds the positions of all the boxes in a two-dimensional graph and uses movebox () to move each box one by one in four directions. If a movement is feasible, add the new status after moving to the vector container and return it to DFS/BFs. The Code is as follows: void sokostate: nextstep (vector <sokostate> & VS) const {sokostate newstate; For (INT I = 1; I <rows _-1; I ++) {for (Int J = 1; j <Cols _-1; j ++) {point P (I, j); If (! Isbox (p) continue; If (movebox (newstate, p, p. down (), P. up (), 'U'). push_back (newstate); If (movebox (newstate, p, p. up (), P. down (), 'D'). push_back (newstate); If (movebox (newstate, p, p. right (), P. left (), 'L'). push_back (newstate); If (movebox (newstate, p, p. left (), P. right (), 'R'). push_back (newstate) ;}} so far, our sokostate seems to be almost complete, but a little bit is missing, that is, operator <. As mentioned in the previous article, the box pushing problem may result in duplicate states after some steps. Therefore, the DFS/BFS algorithm must consider checking duplicate states. DFS/BFS has three optional check policies: linear search, binary search, and hash search. Considering the problem of Box pushing, the state space tree may be relatively large, the number of nodes may be large, and the linear search efficiency may be relatively low. Therefore, linear search is not recommended. On the other hand, if you use Hash Lookup, It is troublesome to prepare a hash function for the sokostate class. So I chose a method that is highly efficient and less troublesome-binary search. It is implemented using the STL set container and requires the sokostate class to provide an operator <operator. The simplest method is to implement bool sokostate: Operator <(const sokostate & Other) const {If (rows _ <Other. rows _) return true; If (rows _> Other. rows _) return false; If (Cols _ <Other. cols _) return true; If (Cols _> Other. cols _) return false; For (INT I = 0; I <rows _; I ++) {for (Int J = 0; j <Cols _; j ++) {If (MAP _ [I] [J] <Other. map _ [I] [J]) return true; If (MAP _ [I] [J]> Other. map _ [I] [J]) return false;} return F Alse;} is actually comparing each data member in the sokostate one by one to split the size. Of course, the steps _ member is used to record the moving step. It has nothing to do with the problem status and is not used for comparison. In fact, if you compare steps _, two sokostate objects that use different steps to reach the same state will be considered as not equivalent, in this way, duplicate state nodes in the search tree cannot be eliminated, resulting in an infinite loop of the DFS/BFS algorithm. Now, the entire sokostate class required by DFS/BFS is ready. However, DFS/BFS also requires the user to provide an afterfindsolution function object to give the execution action and policy when the answer is searched. In this question, I want to do only two things: output the answer step and end the search. So this function is very simple. We are not allowed to reserve function objects. It is okay to use a common function: bool printanswer (const sokostate & S) {S. printanswer (cout); cout <Endl; return true;} You should remember, return a true value to stop the search by DFS/BFs. Well, the last part is our main () function. I don't want to explain it any more. You should understand it at first glance. If you have any questions, you may need to go back to the previous articles. Int main (INT argc, char * argv []) {sokostate initstate; CIN> initstate; cout <initstate; ordercheckdup <sokostate> checkdup; int n = breadthfirstsearch (initstate, printanswer, checkdup); If (n = 0) {cout <"no answer. "<Endl;} return 0;} we started the game as an example. This level is moderate, but I haven't launched it after trying for a long time, so I wrote this program to help me find the answer. The program ran on my machine for more than two seconds and found the answer: [3, 6, u] [2, 6, l] [2, 5, L] [3, 2, D] [4, 2, D] [5, 2, D] [4, 5, R] [4, 6, u] [3, 6, u] [6, 2, R] [2, 4, L] [3, 4, d] [4, 4, d] [2, 6, l] [2, 5, L] [2, 4, d] [6, 3, l] [6, 2, R] [2, 3, R] [6, 3, l] [6, 2, u] [5, 2, u] [4, 2, u] [5, 4, d] [2, 4, R] [3, 4, d] [4, 4, d] [2, 5, L] [2, 4, d] [6, 4, L] [6, 3, l] [6, 2, R] [6, 3, R] [6, 4, R] [6, 5, R] [6, 6, u] [5, 6, u] [4, 6, u] [5, 4, d] [6, 4, L] [6, 3, l] [6, 2, R] [6, 3, R] [6, 4, r] [6, 5, R] [6, 6, u] has run, but there are still many improvements and optimizations. One of them is the space occupied by state storage. You may also notice that in this DFS/BFS algorithm, each node in the search tree represents a State, and the search tree may use a stack or queue container. At the same time, if repeated status checks are required, the same status will be saved in the container used for re-query (which may be vector, set, or hash_set ). That is, the status of a problem will be saved in two copies, although the saved copy in the search tree will be released after the search (I .e. removed from the stack or queue container ), however, this State object is still constructed and destructed once. In fact, we can save only one problem status, rather than two identical problems. The container we need is a more powerful container, which should be sorted and accessed in two or more orders, which is exactly the multi-index containers in the boost library. By using it, we can save only one problematic state, while at the same time implementing the search order of DFS/BFS and the check of set/hash_set.
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