人工智能系列文章目录
前言
本博客记录本科人工智能学习过程,这篇博客主要讲AI中搜索的基本问题,从传统的盲目搜索过渡到要学习的启发式搜索。
一、什么是搜索?
根据问题的实际情况不断寻找可利用的知识,构造出 一条代价较少的推理路线,使问题得到圆满解决的过程称为搜索
包括两个方面:
◼ 找到从初始事实到问题最终答案的一条推理路径
◼ 找到的这条路径在时间和空间上复杂度最小
二、搜索策略
1.搜索分类
根据是否使用启发式信息分类:
▪ 盲目搜索:也称为无信息搜索,即只按预定的控制策略进行搜索,在搜索过程中获得的中间信息
不用来改进控制策略。
▪ 启发式搜索:在搜索中加入了与问题有关的启发性信息,用于指导搜索朝着最有希望的方向进行,加速问题的求解过程并找到最优解。
2.搜索策略评价
- 完备性:如果存在一个解答,该策略是否保证能够找到?
- 时间复杂性:需要多长时间可以找到解答?
- 空间复杂性:执行搜索需要多大存储空间?
- 最优性:如果存在不同的几个解答,该策略是否可以发现最高质量的解答?
三、盲目搜索
盲目搜索一般是按预定的搜索策略进行搜索。由于这种搜索总是按预定的路线进行,没有考虑到问题本身的特性,所以这种搜索具有很大的盲目性,效率不高,不便于复杂问题的求解。
包含:
• 深度优先搜索
• 宽度优先搜索
• 一致代价搜索
• 迭代加深搜索
1.(有界)深度优先搜索(Depth-first,DFS)
◼ 深度优先搜索生成节点并与目标节点进行比较是沿着树的最大深度方向进行的,只有当上次访问的节点不是目标节点,而且没有其他节点可以生成的时候,才转到上次访问节点的父节点。转移到父节点后,该算法会搜索父节点的其它的子节
点。
◼ 防止搜索过程沿着无益的路径扩展下去,往往给出一个节点扩展的最大深度——深度界限。
⚫ Open:未考察节点(节点已生成,已计算f(x), 但未扩展)
⚫ Closed:已考察节点(已扩展)
步骤:
(1)把初始节点S0放入OPEN表
(2)如果OPEN表为空,则问题无解,退出
(3)把OPEN表的第一个节点(记为节点n)取出,放入CLOSED表
(4)考查节点n是否为目标节点.若是,则求得了问题的解,退出
(5)若节点n不可扩展,则转第(2)步
(6)扩展节点n,将其子节点放入OPEN表的首部,并为每一个子节点都配置指向父节 点的指针,转第(2)步
八数码问题:
问题描述:
在3×3的棋盘上,摆有八个棋子,每个棋子上标有1至8的某一数字。棋盘中留有一个空格。空格周围的棋子可以移到空格中。要求解的问题是:给出一种初始布局(
初始状态)和目标布局(目标状态),找到一种最少步骤的移动方法,实现从初始布局到目标布局的转变。
# -*- coding: utf-8 -*-
'''
深度优先搜索实现
'''
import copy
#棋盘的类,实现移动和扩展状态
class grid:
def __init__(self, stat):
self.pre = None
self.target = [[1, 2, 3], [8, 0, 4], [7, 6, 5]]
self.stat = stat
self.find0()
self.update()
#更新深度和距离和
def update(self):
self.fH()
self.fG()
# G是深度,也就是走的步数
def fG(self):
if (self.pre != None):
self.G = self.pre.G + 1
else:
self.G = 0
# H是和目标状态距离之和,可以用来判断是否找到解
def fH(self):
self.H = 0
for i in range(3):
for j in range(3):
targetX = self.target[i][j]
nowP = self.findx(targetX)
self.H += abs(nowP[0] - i) + abs(nowP[1] - j)
#以三行三列的形式输出当前状态
def see(self):
print("depth:", self.G)
for i in range(3):
print(self.stat[i])
print("-" * 10)
# 查看找到的解是如何从头移动的
def seeAns(self):
ans = []
ans.append(self)
p = self.pre
while (p):
ans.append(p)
p = p.pre
ans.reverse()
for i in ans:
i.see()
#找到数字x的位置
def findx(self, x):
for i in range(3):
if (x in self.stat[i]):
j = self.stat[i].index(x)
return [i, j]
#找到0的位置,也就是空白格的位置
def find0(self):
self.zero = self.findx(0)
#对当前状态进行扩展,也就是上下左右移动,返回的列表中是状态的二维列表,不是对象
def expand(self):
i = self.zero[0]
j = self.zero[1]
gridList = []
if (j == 2 or j == 1):
gridList.append(self.left(