Program design final exam review topic three: search

The third topic is the search algorithm.

There are many search algorithms, such as depth-first search (dfs), breadth-first search (bfs), A * algorithm and so on. In this topic, I strive to make dfs and bfs more familiar to me. And some pruning optimizations.

(1) Depth-first search

In order to find a solution to the problem, start from the starting node, find its next node, and then continue to search along this node until there is no next node, go back to its parent node, and view other children of its parent node, If there is, then go down this sub-node, if not, continue to trace back. Until all nodes are traversed.

For example: Fig   Starting from A: A-> B-> E-> C-> F-> H-> G-> D. This is a traversal sequence.

This is the search process of depth-first search.

Implementation: Generally implemented with recursive ideas or stacks .

For the maze problem, enter a two-dimensional array to represent a maze. A value of 1 in the maze means walking, and a value of 0 means not walking. It is required to find a path from the upper left corner to the lower right corner. (General meaning)

Example: poj3984 maze problem ( https://vjudge.net/problem/POJ-3984)

This question specifies a 5X5 two-dimensional array, "0" means walking, "1" means not walking, requires a shortest path from (0, 0) to (4, 4).

Problem Solution: If you use the depth-first search method to solve the problem, you must use recursion.

However, the key to recursion is the conditions for entering recursion and out of recursion next time.

The condition for this problem to enter the next time recursively is that the next node can walk and has not walked before and has not reached the end.

And the condition for recursive termination is: to the end.

So the solution of this question dfs:

Code:

#include<iostream>
using namespace std;

int map[5][5];
int nx[4]={0,1,0,-1};
int ny[4]={1,0,-1,0};
int ans=1e9;
bool final[5][5];
bool vis[5][5];
int cnt=0;

void dfs(int steps,int x,int y)
{
	if(x==4&&y==4)  //终止条件,并且记录最短路径 
	{
		if(steps<ans)
		{
			ans=steps;
			for(int i=0;i<5;i++)
				for(int j=0;j<5;j++)
			    	final[i][j]=vis[i][j]; 	   
		}
		return ;
	}
	int xn,yn;
	for(int i=0;i<4;i++)  
	{
		xn=x+nx[i];yn=y+ny[i];
		if(xn>=0&&xn<=4&&yn>=0&&yn<=4&&!map[xn][yn]&&!vis[xn][yn])
		{
			vis[xn][yn]=true;   //更改为true,不能再走 
			dfs(steps+1,xn,yn);  //递归下去 
			vis[xn][yn]=false;  //为之后记录更短路径 
		}
	}
	return ;
}

int main()
{
	for(int i=0;i<5;i++)
	{
		for(int j=0;j<5;j++)
		{
			cin>>map[i][j];
			vis[i][j]=0;
		}
	}
	dfs(0,0,0);
	cout<<"(0, 0)"<<endl;
	for(int i=0;i<5;i++)
	{
		for(int j=0;j<5;j++)
		{
			if(final[i][j])
			    cout<<"("<<i<<", "<<j<<")"<<endl;
		}
	}
	return 0;
 } 

Pay attention to the writing of recursion and set the vis array from true to false in order to record the shortest path, because of the nature of recursion: the previous journey to the end will not go again. With this understanding, the code I wrote is much simpler than my previous code.

(2) Breadth-first search

The idea of ​​breadth-first search is to start from a node, find all the nodes that this node can reach, record it, and traverse these nodes in sequence. And in the process of traversing, find all the nodes that these nodes can reach and record them. Then traverse these nodes in turn, and find all the nodes that these nodes can reach, record them ... keep traversing in this way until all nodes have been traversed or find the nodes that meet the requirements of the problem.

For example: the Fig   traversal sequence starting from A: A-> B-> C-> D-> E-> F-> G-> H.

This is the breadth-first search process.

Implementation of bfs: Queues are generally used to access nodes. If you want to output the path, you can use the pointer to access the intermediate state.

Note: The path search implemented by bfs must be the shortest, so the optimal path is generally handled by bfs.

Example: The same is the maze problem above (poj3984)

Code:

#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<queue>
using namespace std;

int map[5][5];
int nx[4]={0,1,0,-1};
int ny[4]={1,0,-1,0};
int res;
bool vis[5][5];

struct point
{
	int x,y;
	//point(int n,int m):x(n),y(m)
	//{	};
	point *last;
};

point* bfs()
{
	queue<point *>q;
	point *ans=new point;
	ans->x=0,ans->y=0;
	ans->last=NULL;
	q.push(ans);
	vis[0][0]=true;
	while(!q.empty())
	{
		ans=q.front();q.pop();
		if(ans->x==4&&ans->y==4) return ans;
		int xn,yn;
		for(int i=0;i<4;i++)
		{
			xn=ans->x+nx[i];yn=ans->y+ny[i];
			if(xn>=0&&xn<=4&&yn>=0&&yn<=4&&!map[xn][yn]&&!vis[xn][yn])
			{
				point *e = new point;
				e->x=xn,e->y=yn;
				e->last=ans;
				q.push(e);
				vis[xn][yn]=true;
			}
		}
	}
	return NULL;
}
void output(point *s)
{
	if(s==NULL) return ;
	output(s->last);
	cout<<"("<<s->x<<", "<<s->y<<")"<<endl;
}

int main()
{
	for(int i=0;i<5;i++)
	{
		for(int j=0;j<5;j++)
		{
			cin>>map[i][j];
			vis[i][j]=0;
		}
	}
	output(bfs());
	return 0;
}

Refer to the output process (pointer application): https://blog.csdn.net/acmer_sly/article/details/52492245

The above is the basic application of dfs and bfs. And dfs has an optimization method: pruning optimization (minus the intermediate state that will not reach the target during the intermediate process).

Pruning optimization :

For example: Add another judgment after judging whether the conditions are met.

if(steps>ans) return ;

This will make after finding a path, after ans is assigned, in the subsequent dfs search, if the number of steps is greater than the number of steps of the ans found before. Then such extra steps can be discarded. Because we ask to find the shortest path, if the number of steps is greater than the number of steps found for a complete path, we do not need to consider this new path anymore.

Another pruning: If the current step, the position of the current search point plus the shortest number of steps to reach the end point are greater than the previous result ans, then this path does not need to be considered. code show as below:

if((steps+abs(x-4)+abs(y-4))>ans) return ;

(3) A * algorithm

A * search algorithm, not to repeat. The main idea is to use a criterion to judge the movement of each step. This standard is F, F = G + H. G represents the cost of moving from the starting point to the current position. H represents the cost of the optimal path from the current location to the target location. The F obtained by adding these two costs is used to judge the next move. Finally reach the target position. Then use the pointer to traverse the shortest path.

Recommend a document, I read this to understand the A * algorithm: https://blog.csdn.net/hitwhylz/article/details/23089415

 

Also search for the classic question: The Eight Queens question.

There are a lot of detailed answers to the questions of the Eight Queens on the blog. I will not repeat them here. I picked some blogs that I understand:

The first article did not use recursion. However, the loop judgment conditions such as while and if are used perfectly. Through the loop judgment, the search for a feasible solution is completed. Continue to find the next solution by backtracking. The code is very refined, you can understand it by looking carefully.

https://blog.csdn.net/qq_326324545/article/details/80919368  

The second chapter has non-recursive algorithms and recursive algorithms. I suggest looking at the recursive algorithm, which is almost the same idea as the one above, but uses recursion. The code is more streamlined.

https://www.cnblogs.com/yjd_hycf_space/p/6670316.html

 

Well, the search algorithm is written here, the final exam is coming soon, I do n’t have much time ~~

 

 

 

 

 

Published 6 original articles · liked 0 · visits 184

Guess you like

Origin blog.csdn.net/morning_zs202/article/details/92415046