搜索算法是利用计算机的高性能来有目的地穷举一个问题的部分或所有的可能情况,从而求出问题的解的一种方法。搜索过程实际上是根据初始条件和扩展规则构造一棵解答树并寻找符合目标状态的节点的过程。涉及到的概念包括:状态、状态转移、搜索树、状态空间、可行解、最优解。
一、相关概念
状态:对问题以及事物状态在某一发展阶段的数学描述。
状态转移:问题从一种状态转移到另一种状态的操作。
搜索树:以阶段中每一个状态作为一个点,状态之间的转移作为边,形成一个隐式图。
其中我们把初始状态看做根。那么我们的搜索过程实际上就是在对这个树的结点做遍历。这棵树也可以称为状态空间。
二、搜索算法分类
枚举算法:最直接的搜索方法,列举问题的所有状态.然后从中找出问题的解。
广度优先搜索(BFS):从初始状态开始,通过规则来生成第一层结点,同时检查生成结点中是否有目标结点.若没有则生成下一层接点,并检查是否有目标结点。广度优先搜索通常采用队列存储,每次扩展时都会扩展当前结点的所有子结点。
深度优先搜索(DFS):从初始结点开始扩展,按照某中顺序不断的向下扩展,直到找到目标状态或者是无法继续扩展。深度优先搜索通常用到堆栈存储,当前节点为下一次扩展结点的父节点。
双向广度优先搜索
A*算法
回溯算法
三、简单搜索算法举例
3.1 油田合并
问题描述:某石油公司发现了一个油田。该油田由n*m个单元组成的矩形,有些单元里有石油,有些则没有。单元油田可以通过上,下,左或右连通。在一个单元油田里架设一台采油机,它可以把和该单元油田相连的单元油田的石油采完。该公司想知道最少需要架设几台采油机能把所有的石油采完。
输入:输入2个正整数n,m(1<=n,m<=50)。接着有n行,每行有m个字符。'@'表示该单元有石油,'*'则表示该单元没有石油。
输出:对于每组测试,输出最少需要架设几台采油机。
解答思路:(1)建立数组,用来存储油田分布状态;(2)建立数组,用来存储采油机安装的状态;(3)某一点是否可以放采油机取决于,此地是否有油井,并且,此地的上和左,是否架设了油井,如果架设,本地不再需要,如若没有,在本地放采油机;(4)如果可以放采油机,我们就在原有采油机的基础上再加1。
解答代码:
#include<iostream>
#include<string>
#include<cstdio>
using namespace std;
int dfs(int t,int j);
char data[51][51];//油田分布情况
int flag[51][51];//标记油田
int main()
{
int i,j,n,m;
while(scanf("%d%d",&n,&m)!=EOF)
{
int count=0;
memset(flag,0,sizeof(flag));
for(i=0;i<n;i++)
scanf("%s",data[i]);
for(i=0;i<n;i++)
{
for(j=0;j<m;j++)
if(data[i][j]=='@')
count+=dfs(i,j);
}
printf("%d\n",count);
}
return 0;
}
int dfs(int i,int j)
{
flag[i][j]=1;
if(i-1>=0 && j-1>=0)
{
if(flag[i-1][j]==1 || flag[i][j-1]==1)
return 0;
}
else if(i-1<0 && j-1>=0)
{
if(flag[i][j-1]==1)
return 0;
}
else if(i-1>=0 && j-1<0)
{
if(flag[i-1][j]==1)
return 0;
}
return 1;
}
运行结果:
3.2 老鼠走迷宫:老鼠的走法有上、左、下、右四个方向,在每前进一格之后就选一个方向前进,无法前进时退回选择下一个可前进方向,如此在阵列中依序测试四个方向,直到走到出口为止。
解答代码:
#include<iostream>
#include<fstream>
#define Row 7
#define Col 7
using namespace std;
int m[Row][Col]=
{
{2, 2, 2, 2, 2, 2, 2},
{2, 0, 0, 0, 0, 0, 2},
{2, 0, 2, 0, 0, 0, 2},
{2, 0, 0, 2, 0, 2, 2},
{2, 2, 0, 2, 0, 2, 2},
{2, 0, 0, 0, 0, 0, 2},
{2, 2, 2, 2, 2, 2, 2}
};
int x=1,y=1,xx=5,yy=5;
int sum=0;
void find(int x,int y);
void output();
//ofstream fout("estdout_2.pc2",ios::app);
int main()
{
int i,j;
for(i=0;i<Row;i++)
{
for(j=0;j<Col;j++)
{
if(m[i][j]==2)
cout<<"█";
else
cout<<" ";
}
cout<<endl;
}
cout<<endl<<endl;
find(1,1);
cout<<"所有走法:"<<sum<<endl;
return 0;
}
void find(int x,int y)
{
int t=m[x][y];
m[x][y]=1;
if(x==5&&y==5)
{
sum++;
output();
}
if(m[x+1][y]==0)
{
find(x+1,y);
}
if(m[x-1][y]==0)
{
find(x-1,y);
}
if(m[x][y+1]==0)
{
find(x,y+1);
}
if(m[x][y-1]==0)
{
find(x,y-1);
}
m[x][y]=t;
return ;
}
void output()
{
int i,j;
for(i=0;i<Row;i++)
{
for(j=0;j<Col;j++)
{
if(m[i][j]==2)
{
cout<<"█";
}
else if(m[i][j]==0)
{
cout<<" ";
}
else
{
cout<<"◇";
}
}
cout<<endl;
}
cout<<endl;
}
运行结果: