搜索算法入门

本文将讨论一个简单的搜索算法:深度优先搜索DFS

DFS的思想可以概括为:选择一个方向,一直往前走,直到无路可走。再回到有其他路可走的结点,重复上述步骤 ,直到回到出发点。

实际上就是一个递归的思想。

先来看一个递归求阶乘的例子。

f(n)=n!,f(n)=n*f(n-1);...可以看成为从n开始,不断减1遍历,直到n变为1(递归结束点,也就是这条路已经无路可走了)。虽然这个例子只有一条路,但也可以看作是从n开始的深度优先遍历。

int fun(int n)
{
	if(n==1)return 1;
	return n*fun(n-1);
}


再来看个题目:http://acm.hdu.edu.cn/showproblem.php?pid=1241

Problem Description
The GeoSurvComp geologic survey company is responsible for detecting underground oil deposits. GeoSurvComp works with one large rectangular region of land at a time, and creates a grid that divides the land into numerous square plots. It then analyzes each plot separately, using sensing equipment to determine whether or not the plot contains oil. A plot containing oil is called a pocket. If two pockets are adjacent, then they are part of the same oil deposit. Oil deposits can be quite large and may contain numerous pockets. Your job is to determine how many different oil deposits are contained in a grid. 
 

Input
The input file contains one or more grids. Each grid begins with a line containing m and n, the number of rows and columns in the grid, separated by a single space. If m = 0 it signals the end of the input; otherwise 1 <= m <= 100 and 1 <= n <= 100. Following this are m lines of n characters each (not counting the end-of-line characters). Each character corresponds to one plot, and is either `*', representing the absence of oil, or `@', representing an oil pocket.
 

Output
For each grid, output the number of distinct oil deposits. Two different pockets are part of the same oil deposit if they are adjacent horizontally, vertically, or diagonally. An oil deposit will not contain more than 100 pockets.
 

Sample Input
 
  
1 1 * 3 5 *@*@* **@** *@*@* 1 8 @@****@* 5 5 ****@ *@@*@ *@**@ @@@*@ @@**@ 0 0
 

Sample Output
 
  
0 1 2 2



题目意思就是,*代表没有油田,@代表油田。要注意的是,相邻(周围8个,上下左右,左上左下右上右下)的油田看作为同一个油田,要求算出地图中油田的个数。

题目很好理解,那么,要计算油田个数,只需要,从某个油田开始搜索,分别往8个方向搜索,如果找到了相邻油田,则继续在这个油田往8个方向搜索,看起来就是不断往深处搜索,所以叫作深度优先搜索。

#include<iostream>
using namespace std;

char map[105][105];
int ans;
int road[8][2]={{1,0},{-1,0},{0,-1},{0,1},{1,1},{1,-1},{-1,-1},{-1,1}};
int n,m;
void dfs(int i,int j){
    map[i][j]='*';
    for(int k=0;k<8;k++){
        int x=i+road[k][0];
        int y=j+road[k][1];
        if((x>=0&&y>=0)&&(x<m&&y<n)&&map[x][y]=='@'){        //find oil                        
            dfs(x,y);
        }
    }
    return;
}

int main()
{
//    freopen("E:\\in.txt","r",stdin);
    int i,j;
    while(scanf("%d%d",&m,&n))
   {
      ans=0;
      if(m==0&&n==0) break;
      for(i=0;i<m;i++)
      {
         scanf("%s",map[i]);
      }
      for(i=0;i<m;i++)
      {
         for(j=0;j<n;j++)
         {
            if(map[i][j]=='@')
            {
               ans++;
               dfs(i,j);
            }
         }
      }
      printf("%d\n",ans);
   }
    return 0;
}


从代码中也很好的理解DFS,如果某个方向搜索到的结果满足条件,则继续往深处搜索,否则返回。


下面再讨论一下基于DFS的记忆化搜索。实际上是动态规划问题。

看个题目:http://acm.hdu.edu.cn/showproblem.php?pid=1078

Problem Description
FatMouse has stored some cheese in a city. The city can be considered as a square grid of dimension n: each grid location is labelled (p,q) where 0 <= p < n and 0 <= q < n. At each grid location Fatmouse has hid between 0 and 100 blocks of cheese in a hole. Now he's going to enjoy his favorite food.

FatMouse begins by standing at location (0,0). He eats up the cheese where he stands and then runs either horizontally or vertically to another location. The problem is that there is a super Cat named Top Killer sitting near his hole, so each time he can run at most k locations to get into the hole before being caught by Top Killer. What is worse -- after eating up the cheese at one location, FatMouse gets fatter. So in order to gain enough energy for his next run, he has to run to a location which have more blocks of cheese than those that were at the current hole.

Given n, k, and the number of blocks of cheese at each grid location, compute the maximum amount of cheese FatMouse can eat before being unable to move. 
 

Input
There are several test cases. Each test case consists of 

a line containing two integers between 1 and 100: n and k 
n lines, each with n numbers: the first line contains the number of blocks of cheese at locations (0,0) (0,1) ... (0,n-1); the next line contains the number of blocks of cheese at locations (1,0), (1,1), ... (1,n-1), and so on. 
The input ends with a pair of -1's. 
 

Output
For each test case output in a line the single integer giving the number of blocks of cheese collected. 
 

Sample Input
 
  
3 1 1 2 5 10 11 6 12 12 7 -1 -1
 

Sample Output
 
  
37


题目大意:从(1,1)开始,每次最多可以移动k个单位,所到达的下一个单位的数值必须必上一个单位的数值大。问和最大是多少。

从输入案例来看,最大的路径就是:1--2--5--6--11--12。

递归加动态规划的思想解决这个问题

#include<iostream>
using namespace std;

#define maxn 105
int map[maxn][maxn];
int ds[maxn][maxn];
int cnt,m,n;
int road[4][2]={{0,1},{0,-1},{1,0},{-1,0}};
int dfs(int i,int j){
	int temp,max=0;
	if(ds[i][j]<0){
		for(int l=1;l<=m;l++){
			for(int k=0;k<4;k++){
				int x=i+l*road[k][0];
				int y=j+l*road[k][1];
				if(x>=0 && y>=0 && x<n && y<n && map[x][y]>map[i][j]){
					temp=dfs(x,y);
					if(temp>max)	max=temp;
				}
			}
		}
		ds[i][j]=max+map[i][j];
	}
	return ds[i][j];
}

int main()
{
	freopen("E:\\in.txt","r",stdin);
	while(cin>>n>>m){
		if(n==-1&&m==-1)break;
		memset(ds,-1,sizeof(ds));
		int i,j;
		for(i=0;i<n;i++){
			for(j=0;j<n;j++){
				cin>>map[i][j];
			}
		}
		cnt=0;
		cnt=dfs(0,0);
		cout<<cnt<<endl;
	}
	return 0;
}



发布了54 篇原创文章 · 获赞 62 · 访问量 10万+

猜你喜欢

转载自blog.csdn.net/u013053268/article/details/50687526