3.4 无信息搜索策略
无信息搜索算法不提供有关某个状态与目标状态的接近程度的任何线索。 也就是说,这个策略并不能提前知道其选择带来的代价是多少。
(1)广度优先搜索算法
BFS算法(即层次遍历),先扩展根节点,然后扩展根节点的所有后继节点,再扩展后继节点的后继,以此类推。 为了减少其计算代价,一般选择早期目标测试策略,即在生成节点后立即检查该节点是否为一个解,而不是像最 佳优先搜索使用的后期目标测试(late goal test)那样,等节点弹出队列后再检查该节点是否为 一个解。
vector<int>visited;//记录节点是否访问
queue<int>q;//队列
q.insert(adj[0][0]);//先插入起始节点
while(!q.empty()){//当队列不为空时,继续搜索
intn=q.size();//当前层一共多少节点
while(n--){//搜索完当前层所有节点进入下一层
intnode=q.front();q.pop();//出队
auto&tmp=adj[node];//当前节点的所有邻接节点
for(auto&next:tmp){if(visited[next])continue;//若节点已经访问,则跳过
visited[next]=true;//否则访问该节点,并且标记已经访问
q.insert(next);//该节点加入队列
}}
(2)Dijkstra算法
在人工智能领域称为一致代价搜索
迪杰斯特拉算法是一个最短路径的方法
它在确立出发点的基础上,设出发点是start,你想到达的点是end,其中一共有n个点,我们可以先找一步到达的距离,然后与分两步到达的距离比较,取最小值,然后让得到的结果与三步到达的距离比较,取最小值,最终让得的的最小值与n-1部到达的距离比较,取最小值,这样的最小值就是我们要得到的距离最少的最优点了。
int n;
int mpt[MAXN][MAXN];
int dis[MAXN];
int vis[MAXN];
int dij(int s,int e)//通过近的点松弛远的点
{
int i,j;
for(i=1;i<=n;i++)//初始化节点
{
dis[i]=mpt[s][i];//也可初始化为inf,不过下面的vis[s]=1必须去掉
vis[i]=0;
}
dis[s]=0;
vis[s]=1;
for(i=1;i<=n;i++)//最多松弛n次
{
int min=inf,t=0;
for(j=1;j<=n;j++)//找出距源点最近的且未访问的点
if(vis[j]==0&&dis[j]<min)
min=dis[t=j];
if(min==inf) break;//松弛完毕,退出
vis[t]=1;
for(j=1;j<=n;j++)//松弛
if(vis[j]==0&&dis[j]>dis[t]+mpt[t][j])//标记过的点都是比当前点近的点,通过当前点不能松弛比它更接近源点的点
dis[j]=dis[t]+mpt[t][j];
}
return (dis[e]==inf)?-1:dis[e];
}
int main()
{
int i,j;
while(scanf("%d",&n)!=EOF&&n!=-1)
{
memset(mpt,1,sizeof(mpt));//图初始化,1表示字节数,视情况而定
//存图
int ans=dij(s,e);
printf("%d\n",ans);
}
return 0;
}
(3)深度优先搜索与内存问题
深度优先搜索(Depth First Search),是图遍历算法的一种。用一句话概括就是:“一直往下走,走不通回头,换条路再走,直到无路可走”。
深度优先搜索策略面对有环状态空间可能会陷入无限循环的的漏洞,但其在内存消耗上的优势可以弥补这一缺陷。
深度优先的树状搜索所花费的时间与状态数成正 比,其空间复杂性仅为 O(bm),其中 b 是分支因子,m 是树的最大深度。有些问题在广度优先 搜索时需要 EB 量级的内存,而在深度优先搜索时仅需要 KB 量级。由于其对内存的节约使用, 深度优先树状搜索已经成为许多人工智能领域的基本工具,例如,约束满足(第 6 章)、命题 可满足性(第 7 章)和逻辑编程(第 9 章)
(4)深度受限和迭代加深搜索
深度受限搜索是深度优先搜索的改进版本,通过设定深度阈值,来使得算法不会陷入无意义的死循环,但是阈值的设定一直以来都是一件非常玄学的事情(。
为了解决玄学问题,提出了迭代加深搜索算法
int max_depth = min_depth;
Id_Dfs( int current_depth , int max_depth ) {
if( current_depth > max_depth ) return ;
if( 找到答案 ){ 输出答案 ; (exit(0) ; || return ;) }
for each ( 当前节点的儿子节点 )
Id_Dfs(current_depth + 1, max_depth) ;
}
for(; ; max_depth++ ) {
Id_Dfs( 0 , i ) ;
}
其特点在于由于大部分搜索树顶端附近的状态重复也并不影响其复杂度(大多数节点位于底层),因此其在内存有限条件下是非常有用的搜索算法。
(4)双向搜索
其定义为同时从初始状态正向搜索和从 目标状态反向搜索,直到这两个搜索相遇。算法的动机是,bd/2 + bd/2 要比 bd 小得多(例如,当 b = d = 10 时,复杂性不到之前算法的五万分之一)
双向最佳优先算法:核心是使用一个评估函数 f(n)给每个节点估计他们的评价值。 每次搜索时优先扩展最有希望的未扩展节点。它包括贪婪最佳优先搜索和A*搜索两个算法。
(贪婪最佳优先搜索: