热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

实用算法实现-第13篇搜索(盲目搜索)

在人工智能中,盲目搜索是相对于启发式搜索来说的。13.1广度优先搜索《算法导论》中,广度优先(Breadth-First)搜索树的伪代码如下:BFS(G,s)

在人工智能中,盲目搜索是相对于启发式搜索来说的。

13.1    广度优先搜索

《算法导论》中,广度优先(Breadth-First)搜索树的伪代码如下:

BFS(G,s)

1  for each vertex u ∈ V[G] - {s}

2       docolor[u] ← WHITE

3          d[u] ← ∞

4          ∏[u] ← NIL

5  color[s] ← GRAY

6  d[s] ← 0

7  ∏[s] ← NIL

8  Q ← Ф

9 ENQUEUE(Q, s)

10while Q ≠ Ф

11      do u ← head[Q]

12         for each v ∈ Adj[u]

13             doif color[v] = WHITE

14                   thencolor[v] ← GRAY

15                        d[v] ← d[u] + 1

16                        ∏[v] ← u

17                        ENQUEUE(Q,v)

18         color[u] ← BLACK

13.1.1   实例

PKU JudgeOnline, 3669, Meteor Shower.

13.1.2   问题描述

初始位置在原点,所站的地方隔一段时间之后就要被砸,被砸的时候和以后该地方都不能待,要逃到一个安全的地方。问最少需要多少步才能到一个安全的地方。

PKU JudgeOnline, 3414, Pots是对状态空间的BFS搜索。

13.1.3   输入

4

00 2

21 2

11 2

03 5

13.1.4   输出

5

13.1.5   程序

#include 
#include 
#include 
int map[1002][1002];
bool visited[1002][1002];
int depth[1002][1002];
int queue[150100][2];
int top;
int adj[5][2] = {{0, 0}, {0, -1}, {0, 1}, {-1, 0}, {1, 0}};
#define  enqueue(i, j) queue[top][0] = i;queue[top][1] = j;top++;
#define MAX 0x7F7F7F7F
inline void dequeue(int *i, int *j)
{
     top--;
     *i = queue[top][0];
     *j = queue[top][1];
}
int main()
{
     //freopen("meteor.12.in","r", stdin);
    //freopen("out.out","w", stdout);
     int M;
     int i;
     int j;
     int tempX;
     int tempY;
     inttempTime;
     int X;
     int Y;
     int min;
     scanf("%d",&M);
     memset(map, 0x7F, sizeof(map));
     for(i = 0;i = 0&&Y >= 0)&&
              (map[X][Y] > tempTime)){
                   map[X][Y] = tempTime;
              }
         }
     }
     memset(visited, 0, sizeof(visited));
     depth[0][0] = 0;
     top = 0;
     enqueue(0, 0);
     visited[0][0] = true;
     min = MAX;
     for(i=0;i= 0&&Y >= 0)&&
              (map[X][Y] >tempTime)&&
              (visited[X][Y] == false)){
                   enqueue(X, Y);
                   visited[X][Y] = true;
                   depth[X][Y] = tempTime;
                   if(map[X][Y]== MAX){
                       if(min> depth[X][Y]){
                            min = depth[X][Y];
                       }
                       gotofind;
                   }
              }
         }
     }
find:
     if(min ==MAX){
         printf("-1\n");
     }else{
         printf("%d\n",min);
     }
/*   for(i = 0; i <2; i++)
     {
         for(j = 0; j<2 ; j++)
         {
              cout< 
 

13.2    代价一致搜索

当所有路径耗散相等的时候,广度优先搜索是最优的,因为它总是先扩展深度最浅的结点。更一般地,如果路径耗散是结点深度的非递减函数,广度优先搜索也是最优的。

而代价一致(UniformCost)搜索扩展的是路径消耗最低的结点。而如果搜有单独耗散都相等的话,这种算法就和广度优先搜索算法是一样的。

代价一致搜索对一条路径的步数并不关心,而关心所经历步骤总的消耗。因此,在扩展到一个具有能返回同一状态的零耗散行动的结点时就会陷入无限循环。

在实现上,广度优先搜索只需要使用先进先出队列,而代价一致搜索则需要使用优先级队列。

PKU JudgeOnline, 2312, Battle City是典型的代价一致搜索算法的实例。具体分析参看最小堆部分。

13.3    深度优先搜索

算法导论中,深度优先(Depth-First)搜索树的伪代码如下:

DFS(G)

1  for each vertex u ← V[G]

2       docolor[u] ← WHITE

3          [u] ← NIL

4  time ← 0

5  for each vertex u ∈ V[G]

6       do if color[u] = WHITE

7             then DFS-VISIT(u)

13.3.1   实例

PKU JudgeOnline, 2386,Lake Counting.

13.3.2   问题描述

       一块地上有一些水洼,计算一共有多少水洼。

13.3.3   输入

1012

W........WW.

.WWW.....WWW

....WW...WW.

.........WW.

.........W..

..W......W..

.W.W.....WW.

W.W.W.....W.

.W.W......W.

..W.......W.

13.3.4   输出

3

13.3.5   分析

       其实这个题目也可以用BFS来实现了。

13.3.6   程序

#include 
#include 
#define VISITED    '*'
#define UNVISITED  'W'
#define BOUND '.'
#define UP         -1
#define DOWN  1
#define LEFT  -1
#define RIGHT 1
#define NOP        0
int move[8][2]={{UP, NOP}, {UP, RIGHT}, {NOP, RIGHT}, {DOWN, RIGHT}, {DOWN,NOP}, {DOWN, LEFT}, {NOP, LEFT}, {UP, LEFT}};
int num;
int row;
int column;
char grid[102][102];
void DFS_Visit(int a,int b)
{
     grid[a][b] = VISITED;
     //num++;
     //always click onan X
     int i;
     inttempRow;
     inttempColumn;
     char temp;
     for(i = 0;i <8; i++){
         tempRow = a + move[i][0];
         tempColumn = b + move[i][1];
         temp = grid[tempRow][tempColumn];
         if(temp== UNVISITED){
              DFS_Visit(tempRow, tempColumn);
         }else if((temp == BOUND)&&
         (move[i][0] == 0||move[i][1] == 0)){
         }
     }
     return;
}
int main()
{
     int i;
     int j;
     cin >> row >> column;
     if(row == 0&& column == 0){
         return1;
     }
     memset(grid, BOUND, sizeof(grid));
     for(i = 1;i <= row; i++){
         for(j =1; j <= column; j++){
              cin >> grid[i][j];
         }
     }
     num = 0;
     for(i = 1;i <= row; i++){
         for(j =1; j <= column; j++){
              if(grid[i][j]== UNVISITED){
                   num++;
                   DFS_Visit(i, j);
              }
         }
     }
     cout < 
 
13.4    深度有限搜索

使用深度优先搜索的一个危险在于,如果所期待的解处在一个有限的深度上,而树的某个子树深度却无穷大,那么使用它深度优先搜索就很有可能陷入无限的搜索当中,而不能找到这个本来应该可以找到的解。而这种情况又是很可能发生的。

故此深度有限搜索(Depth-Limited),就引入对搜索深度的限制,将所有深度达到某限度的结点都看做是没有子结点,即可避免陷入无限的搜索当中。

13.5    迭代加深的深度优先搜索

《人工智能,一种现代方法》和《人工智能,复杂问题求解的结构和策略》介绍了迭代加深(Iterative Deepening)的深度优先搜索的思想。

迭代加深的深度优先搜索是对于深度优先搜索和广度优先搜索的一个很好的折衷,这种平衡是通过对深度优先搜索使用一个界限。

因为折衷算法一层层地搜索空间,所以它保证所发现的目标路径是最短的。这一点和广度优先搜索是一致。

又因为它实质上是一种深度优先搜索,所以它不需要广度优先搜索指数级别那么大的空间要求,这一点上是和深度优先搜索是类似的。

RichardE. Korf似乎对搜索算法贡献很大。对于迭代加深的深度搜索的效率,他指出:因为树上某一给定层的结点数量随着深度呈指数增长,所以几乎所有的时间都花在最深层上,因为即使以算数递增的速度多次产生较浅层也无所谓。

而实际上,有趣的是:尽管看起来迭代加深的深度优先方法在时间上比深度优先搜索和广度优先搜索效率低,但是实际上它的复杂度与两个方法处于同一个数量级,即O(B^n)。其中B为结点的平均孩子数,n为目标结点所在的层次。

13.5.1   实例

PKU JudgeOnline, 3009, Curling 2.0.

13.5.2   问题描述


       如上图,一个游戏是在冰面上滑动石块,有如下规则:

       1. 如果石块紧靠着一堵墙,那么石块不能朝该方向滑动。否则石块可以朝着该方向滑动。

       2. 如果滑动的过程中,石块遇到一堵墙,石块停在墙的前面,并把墙夷为平地。否则一直向前滑。

       3. 如果石块滑出区域,游戏失败。

       4. 如果石块到达目的地,游戏成功。

       5. 如果十步之内没有到达目的地,游戏失败。

       问题是找出从出发点到目的地所需要的步数。

13.5.3   输入

21

32

66

10 0 2 1 0

11 0 0 0 0

00 0 0 0 3

00 0 0 0 0

10 0 0 0 1

01 1 1 1 1

61

11 2 1 1 3

61

10 2 1 1 3

121

20 1 1 1 1 1 1 1 1 1 3

131

20 1 1 1 1 1 1 1 1 1 1 3

0 0

13.5.4   输出

1

4

-1

4

10

-1

13.5.5   分析

最基本的迭代加深的深度优先搜索就可以解决这个题目,而且非常自然。据说DFS配合剪枝也可以解决。

13.5.6   程序

#include 
#include 
#define maxNum 22
#define VISITED    '*'
#define UNVISITED  'W'
#define BOUND '.'
#define UP         -1
#define DOWN  1
#define LEFT  -1
#define RIGHT 1
#define NOP        0
int move[4][2]={{UP, NOP}, {NOP, RIGHT}, {DOWN, NOP}, {NOP, LEFT}};
int num;
int row;
int column;
int grid[maxNum][maxNum];
int depth;
int maxDepth;
int StartX;
int StartY;
int IDDFS_Visit(int a, int b)
{
     int i;
     inttempRow;
     int tempColumn;
     intstoneRow;
     intstoneColumn;
     char temp;
     depth++;
     int find;
     find = 0;
     if(depth> maxDepth){
         gotoend;
     }
     for(i = 0;i <4; i++){
         tempRow = a + move[i][0];
         tempColumn = b + move[i][1];
         if((tempRow<1 ||  tempColumn <1)
         ||(tempRow > row || tempColumn >column)
         ||(grid[tempRow][tempColumn] == 1))
         {//紧接着的是边界或者砖头
              continue;
         }
         while((tempRow>= 1 && tempColumn >= 1)
         && (tempRow <= row&& tempColumn <= column)){
              temp = grid[tempRow][tempColumn];
              if(temp== 3){
                   find = 1;
                   gotoend;
              }elseif(temp == 1){
                   break;
              }
              stOneRow= tempRow;
              stOneColumn= tempColumn;
              tempRow = tempRow + move[i][0];
              tempColumn = tempColumn +move[i][1];
         }
         if(tempRow<1 ||  tempColumn <1
         || tempRow > row || tempColumn >column)
         {//一直滑出了边界
              continue;
         }
         grid[tempRow][tempColumn] = 0;
         find = IDDFS_Visit(stoneRow,stoneColumn);
         grid[tempRow][tempColumn] = 1;
         if(find== 1)
         {       
              gotoend;
         }
     }
end:
     depth--;
     returnfind;
}
int main()
{   
     int i;
     int j;
     while(scanf("%d%d", &column, &row))
     {
         if(row== 0 && column == 0)
         {
              break;
         }
         memset(grid, 0, sizeof(grid));
         for(i =1; i <= row; i++){
              for(j= 1; j <= column; j++){
                   scanf("%d", &grid[i][j]);
                   if(grid[i][j]== 2){
                       StartY = i;
                       StartX = j;
                   }
              }
         }
         for(maxDepth= 1; maxDepth <= 10; maxDepth++)
         {
              depth = 0;
              if(IDDFS_Visit(StartY,StartX) == 1)
              {
                   break;
              }
         }
         if(maxDepth> 10){
              printf("-1\n");
         }else{
              printf("%d\n",maxDepth);
         }
     }
}

13.6    双向搜索

     双向搜索(Bidirectional)是同时从源结点和目标结点对状态进行搜索。要使用双向搜索首先要同时知道源结点和目标结点的状态,其次要保证从两个状态开始的两个方向的搜索是可行的。

13.7    总结

《人工智能,一种现代方法》对于几种搜索策略的介绍相当深入、细致。讨论了广度优先搜索、代价一致搜索、深度优先搜索、深度有限(Depth-Limited)搜索、迭代深入深度优先搜索、双向搜索(Bidirectional)等无信息的搜索策略。

对于搜索策略,可以从以下几个标准进行评价:

1. 是否完备?即:当问题有解时,这个算法能够找到一个解。

2. 是否最优?即:这个搜索策略是否找到最优解。

3. 时间复杂度。即:找到一个解需要花费多长时间。

4. 空间复杂度。即:执行搜索过程需要多少内存。

该文还总结了下表:

13.8    实例

13.8.1   广度优先搜索算法实例

PKU JudgeOnline, 3170, Knights of Ni.

PKU JudgeOnline, 3669, Meteor Shower.

PKU JudgeOnline, 3126, Prime Path.

PKU JudgeOnline, 2251, Dungeon Master.

PKU JudgeOnline, 3414, Pots.

13.8.2   代价一致搜索实例

PKU JudgeOnline, 2312, Battle City

13.8.3   深度优先搜索算法实例

PKU JudgeOnline, 1562, Oil Deposits.

PKU JudgeOnline, 2386, Lake Counting.

PKU JudgeOnline, 1111, Image Perimeters.

PKU JudgeOnline, 3620, Avoid The Lakes.

13.8.4   迭代加深的深度优先搜索实例

PKU JudgeOnline, 3009, Curling 2.0.

本文章欢迎转载,请保留原始博客链接http://blog.csdn.net/fsdev/article

推荐阅读
  • 题目解析给定 n 个人和 n 种书籍,每个人都有一个包含自己喜好的书籍列表。目标是计算出满足以下条件的分配方案数量:1. 每个人都必须获得他们喜欢的书籍;2. 每本书只能分配给一个人。通过使用深度优先搜索算法,可以系统地探索所有可能的分配组合,确保每个分配方案都符合上述条件。该方法能够有效地处理这类组合优化问题,找到所有可行的解。 ... [详细]
  • 兆芯X86 CPU架构的演进与现状(国产CPU系列)
    本文详细介绍了兆芯X86 CPU架构的发展历程,从公司成立背景到关键技术授权,再到具体芯片架构的演进,全面解析了兆芯在国产CPU领域的贡献与挑战。 ... [详细]
  • 三角测量计算三维坐标的代码_双目三维重建——层次化重建思考
    双目三维重建——层次化重建思考FesianXu2020.7.22atANTFINANCIALintern前言本文是笔者阅读[1]第10章内容的笔记,本文从宏观的角度阐 ... [详细]
  • 在机器学习领域,深入探讨了概率论与数理统计的基础知识,特别是这些理论在数据挖掘中的应用。文章重点分析了偏差(Bias)与方差(Variance)之间的平衡问题,强调了方差反映了不同训练模型之间的差异,例如在K折交叉验证中,不同模型之间的性能差异显著。此外,还讨论了如何通过优化模型选择和参数调整来有效控制这一平衡,以提高模型的泛化能力。 ... [详细]
  • xmpphp测试openfire发布信息
    xmpphp测试openfire发布信息1.先下载xmpphp,地址:https:code.google.compxmpphpdownloadslist2.编写php脚本。<?php ... [详细]
  • 【线段树】  本质是二叉树,每个节点表示一个区间[L,R],设m(R-L+1)2(该处结果向下取整)左孩子区间为[L,m],右孩子区间为[m ... [详细]
  • Leetcode学习成长记:天池leetcode基础训练营Task01数组
    前言这是本人第一次参加由Datawhale举办的组队学习活动,这个活动每月一次,之前也一直关注,但未亲身参与过,这次看到活动 ... [详细]
  • 本文详细介绍了 Spark 中的弹性分布式数据集(RDD)及其常见的操作方法,包括 union、intersection、cartesian、subtract、join、cogroup 等转换操作,以及 count、collect、reduce、take、foreach、first、saveAsTextFile 等行动操作。 ... [详细]
  • MySQL初级篇——字符串、日期时间、流程控制函数的相关应用
    文章目录:1.字符串函数2.日期时间函数2.1获取日期时间2.2日期与时间戳的转换2.3获取年月日、时分秒、星期数、天数等函数2.4时间和秒钟的转换2. ... [详细]
  • T15483.【清华集训2017模拟11.26】简单路径T25484.【清华集训2017模拟11.26】快乐树T35485.【清华集训2017模拟11.26】字符串T1结论题,结论很 ... [详细]
  • 非计算机专业的朋友如何拿下多个Offer
    大家好,我是归辰。秋招结束后,我已顺利入职,并应公子龙的邀请,分享一些秋招面试的心得体会,希望能帮助到学弟学妹们,让他们在未来的面试中更加顺利。 ... [详细]
  • 本文介绍如何使用OpenCV和线性支持向量机(SVM)模型来开发一个简单的人脸识别系统,特别关注在只有一个用户数据集时的处理方法。 ... [详细]
  • 本文介绍了几种常用的图像相似度对比方法,包括直方图方法、图像模板匹配、PSNR峰值信噪比、SSIM结构相似性和感知哈希算法。每种方法都有其优缺点,适用于不同的应用场景。 ... [详细]
  • 本文介绍如何使用 Python 的 DOM 和 SAX 方法解析 XML 文件,并通过示例展示了如何动态创建数据库表和处理大量数据的实时插入。 ... [详细]
  • 利用爬虫技术抓取数据,结合Fiddler与Postman在Chrome中的应用优化提交流程
    本文探讨了如何利用爬虫技术抓取目标网站的数据,并结合Fiddler和Postman工具在Chrome浏览器中的应用,优化数据提交流程。通过详细的抓包分析和模拟提交,有效提升了数据抓取的效率和准确性。此外,文章还介绍了如何使用这些工具进行调试和优化,为开发者提供了实用的操作指南。 ... [详细]
author-avatar
长白山天翼张薇_955
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有