为了完成人工智能与机器学习实验报告 。。。
本文只需要用到 四个 包
#import 相关包
import copy
import numpy as np
import random
from datetime import datetime
逆序数判断八数码问题是否有解
#逆序数判断:
def solution_or_not(initial,goal):
initial = initial.replace(" ","") #剔除字符串内空格
goal = goal.replace(" ","")
init_num = 0 #initial逆序数
goal_num = 0 #goal逆序数
for i in range(1,9): #计算initial逆序数
temp = 0
for j in range(0,i):
if initial[j] > initial[i] and initial[i]!='0':
temp=temp+1
init_num = init_num + temp
for i in range(1,9): #计算goal逆序数
temp = 0
for j in range(0,i):
if goal[j] > goal[i] and goal[i]!='0':
temp=temp+1
goal_num = goal_num + temp
if(init_num%2) != (goal_num%2): #判断两逆序数的奇偶性是否相等
return 0
else:
return 1
为了解决八数码问题(移动和判断往哪里移动)需要的一些函数
#寻找target的位置
def find_local(arr,target): #arr是节点的list,target是寻找的目标
for i in arr:
for j in i:
if j == target:
return arr.index(i),i.index(j) #返回target的下标
#交换位置,并获得子节点
def get_child(arr,e):
arr_new = copy.deepcopy(arr) #深拷贝,复制一份新的节点
r, c = find_local(arr_new,'0') #寻找0的位置的坐标
r1, c1 = find_local(arr_new,e) #寻找可交换的位置的坐标
#交换位置
arr_new[r][c], arr_new[r1][c1] = arr_new[r1][c1], arr_new[r][c]
return arr_new
#获取可与0交换的元素
def get_elements(arr):
r,c =find_local(arr,'0') #寻找0的的下标
elements=[]
if r > 0:
elements.append(arr[r - 1][c]) # 上边的数
if r < 2:
elements.append(arr[r + 1][c]) # 下边的数
if c > 0:
elements.append(arr[r][c - 1]) # 左边的数
if c < 2:
elements.append(arr[r][c + 1]) # 右边的数
return elements
#曼哈顿距离
def mhd_distance(arr1,arr2):
distance = []
for i in arr1:
for j in i:
loc1 = find_local(arr1,j)
loc2 = find_local(arr2,j)
distance.append(abs(loc1[0] + loc2[0]) + abs(loc1[1] - loc2[1]))
return sum(distance)
#不在位数
def not_digits(arr1,arr2):
num=0
for i in range(0,2):
for j in range(0,2):
if arr1[i][j] != arr2[i][j] and arr1[i][j] != 0 and arr2[i][j]!= 0:
num = num+1
return num
创建一个节点类,用来储存每一个八数码的状态
#设置节点类
class state:
#state为八码数的list表示,parent为父节点
#deep为节点深度,cost为节点代价
#distance为曼哈顿距离,nd_nums为不在位数
def __init__(self, state, parent, deep, cost ,distance ,nd_nums):
self.state = state
self.parent = parent
self.deep = deep
self.cost = cost
self.distance = distance
self.nd_nums= nd_nums
def get_children(self): #获取一层子节点
children=[]
for i in get_elements(self.state):
#逐个元素与0交换位置,生成子节点child
child = state(state=get_child(self.state,i),
parent = self,
deep = self.deep+1,
cost = self.cost+1,
distance = self.distance + mhd_distance(self.state,goal_arr),
nd_nums = not_digits(self.state,goal_arr))
#将每一个交换结果(子节点)都存入children
children.append(child)
return children
为了实现可视化输出
#打印最短路径
def best_path(n):
if n.parent == None:
return
else:
print("↑")
print(np.array(n.parent.state))
best_path(n.parent)
#画分割线
def draw_line():
print('--' * 20)
print('--' * 20)
print('--' * 20)
#整一个搜索路径:
def search_line(close):
print('搜索路径如下:')
for i in close[:-1]:
print(np.array(i.state))
print('↓')
print(np.array(close[-1].state))
将字符串输入转化为八数码
#将字符串转化为列表
def string_to_list(str):
str_list=list(str)
return [str_list[i:i+3] for i in range(0,len(str_list),3)]
广度优先搜索BFS
#广度优先搜索
def BFS(initial_arr,goal_arr):
open = [initial_arr]
close = []
while len(open) > 0: #OPEN表是否为空表
open_1 = [i.state for i in open] #访问open节点内的state
close_1 = [i.state for i in close]
n = open.pop(0) #删除OPEN队头节点,并且赋值给n
close.append(n) #n注入CLOSE表
if n.state == goal_arr:
print('最优路径如下:')
print(np.array(n.state)) #转换成矩阵打印最终节点
best_path(n)
break
else:
for i in n.get_children(): #添加子节点进OPEN
if i.state not in open_1:
if i.state not in close_1:
open.append(i)
draw_line()
search_line(close)
print('搜索步骤为',len(close) - 1)
深度优先搜索DFS
#深度优先搜索
def DFS(initial_arr,goal_arr):
open = [initial_arr]
close = []
# limit = eval(input('请输入要搜索的深度:'))
limit = 20
while len(open) > 0:
open_2 = [i.state for i in open]
close_2 = [i.state for i in close]
n = open.pop(0)
close.append(n)
if n.state == goal_arr:
print('最优路径如下:')
print(np.array(n.state)) #转换成矩阵打印最终节点
best_path(n)
break
else:
if n.deep < limit:
for i in n.get_children():
if i.state not in open_2:
if i.state not in close_2:
open.insert(0, i) #DFS从前端插入
else:
print('该深度下无解') #循环出去后显示无解
draw_line()
search_line(close)
print('深度为',close[-1].deep,'下的搜索步数为:',len(close) - 2)
一致代价优先搜索UCS
#一致代价优先搜索
def UCS(initial_arr,goal_arr):
open = [initial_arr]
close = []
while len(open) > 0: #OPEN表是否为空表
open_3 = [i.state for i in open] #访问open节点内的state
close_3 = [i.state for i in close]
open_4 = [i.cost for i in open] #OPEN内每个节点的cost
min_index = open_4.index(min(open_4))
n = open.pop(min_index) #删除OPEN队头节点,并且赋值给n
close.append(n) #n注入CLOSE表
if n.state == goal_arr:
print('最优路径如下:')
print(np.array(n.state)) #转换成矩阵打印最终节点
best_path(n)
break
else:
for i in n.get_children(): #添加子节点进OPEN
if i.state not in open_3:
if i.state not in close_3:
open.append(i)
draw_line()
search_line(close)
print('搜索步骤为',len(close) - 1, '权重为',close[-1].cost)
贪婪算法
#贪婪算法
def Greedy(initial_arr,goal_arr):
open = [initial_arr]
close = []
while len(open) > 0: #OPEN表是否为空表
open_1 = [i.state for i in open] #访问open节点内的state
close_1 = [i.state for i in close]
n = open.pop(0) #删除OPEN队头节点(此点排序后为最小距离和),并且赋值给n
close.append(n) #n注入CLOSE表
if n.state == goal_arr:
print('最优路径如下:')
print(np.array(n.state)) #转换成矩阵打印最终节点
best_path(n)
break
else:
for i in n.get_children(): #添加子节点进OPEN
if i.state not in open_1:
if i.state not in close_1:
open.insert(0,i)
open.sort(key = lambda x: x.distance) #按曼哈顿距离进行排序
draw_line()
search_line(close)
print('搜索步骤为',len(close) - 1,'总估价为',close[-1].distance)
A*算法-曼哈顿距离
#A*算法-曼哈顿距离
def AStar_MHT(initial_arr,goal_arr):
open = [initial_arr]
close = []
while len(open) > 0: #OPEN表是否为空表
open_1 = [i.state for i in open] #访问open节点内的state
close_1 = [i.state for i in close]
n = open.pop(0) #删除OPEN队头节点(此点排序后为最小距离和),并且赋值给n
close.append(n) #n注入CLOSE表
if n.state == goal_arr:
print('最优路径如下:')
print(np.array(n.state)) #转换成矩阵打印最终节点
best_path(n)
break
else:
for i in n.get_children(): #添加子节点进OPEN
if i.state not in open_1:
if i.state not in close_1:
open.insert(0,i)
open.sort(key = lambda x: x.distance + x.cost) #按曼哈顿距离+cost 进行排序
draw_line()
search_line(close)
print('搜索步骤为',len(close) - 1,'总估价为',close[-1].cost+close[-1].distance)
A*算法-不在位数
#A*算法-不在位数
def AStar_ND(initial_arr,goal_arr):
open = [initial_arr]
close = []
while len(open) > 0: #OPEN表是否为空表
open_1 = [i.state for i in open] #访问open节点内的state
close_1 = [i.state for i in close]
n = open.pop(0) #删除OPEN队头节点(此点排序后为最小距离和),并且赋值给n
close.append(n) #n注入CLOSE表
if n.state == goal_arr:
print('最优路径如下:')
print(np.array(n.state)) #转换成矩阵打印最终节点
best_path(n)
break
else:
for i in n.get_children(): #添加子节点进OPEN
if i.state not in open_1:
if i.state not in close_1:
open.insert(0,i)
open.sort(key = lambda x: x.nd_nums + x.cost) #按不在位数+cost 进行排序
draw_line()
search_line(close)
print('搜索步骤为',len(close) - 1)
主函数如下
#主函数
if __name__=='__main__':
initial='283 104 765'
goal='123 804 765'
if solution_or_not(initial,goal):
goal_arr = string_to_list(goal)
initial_arr = state(string_to_list(initial),
parent=None,
deep=0,
cost=0,
distance=mhd_distance(string_to_list(initial),goal_arr),
nd_nums=not_digits(string_to_list(initial),goal_arr))
DFS(initial_arr,goal_arr) #深度优先搜索
BFS(initial_arr,goal_arr) #宽度优先搜索
UCS(initial_arr,goal_arr) #一致代价优先搜索
Greedy(initial_arr,goal_arr) #贪婪算法
AStar_MHT(initial_arr,goal_arr) #A*算法-曼哈顿距离
AStar_ND(initial_arr,goal_arr) #A*算法-不在位数
else:
print("从逆序数判断来看,该八数码问题无解")
部分运行结果如下:
将八数码随机打乱
#随机打乱八数码
def random_str(str):
str_list = list(str)
random.shuffle(str_list)
return ''.join(str_list)
对比两个A*算法的时间复杂度
#算法对比
if __name__=='__main__':
initial='283104765'
goal='123804765'
time = []
count = 50
print("A*曼哈顿距离算法:")
for i in range(0,count):
initial = random_str(initial)
goal = random_str(goal)
if solution_or_not(initial,goal):
goal_arr = string_to_list(goal)
initial_arr = state(string_to_list(initial),
parent=None,
deep=0,
cost=0,
distance=mhd_distance(string_to_list(initial),goal_arr),
nd_nums=not_digits(string_to_list(initial),goal_arr))
start = datetime.now()
AStar_MHT(initial_arr,goal_arr) #A*算法-曼哈顿距离
end = datetime.now()
print("第",i+1,"次迭代结束,时间为",end - start)
time.append(end - start)
else:
print("第",i+1,"次迭代结束,该八数码无解")
print('A*曼哈顿距离算法平均耗时:',np.mean(time))
initial='283104765'
goal='123804765'
time = []
print("A*不在为数算法:")
for i in range(0,count):
initial = random_str(initial)
goal = random_str(goal)
if solution_or_not(initial,goal):
goal_arr = string_to_list(goal)
initial_arr = state(string_to_list(initial),
parent=None,
deep=0,
cost=0,
distance=mhd_distance(string_to_list(initial),goal_arr),
nd_nums=not_digits(string_to_list(initial),goal_arr))
start = datetime.now()
AStar_ND(initial_arr,goal_arr) #A*算法-不在位数
end = datetime.now()
print("第",i+1,"次迭代结束,时间为",end - start)
time.append(end - start)
else:
print("第",i+1,"次迭代结束,该八数码无解")
print('A*不在位数算法平均耗时:',np.mean(time))
部分运行结果如下 :
八数码问题的代码基于博主AlphaJun_zero的思路做出部分修改,完善与改进
AlphaJun_zerohttps://blog.csdn.net/Juuunn
源代码下载(Jupyter)
人工智能八数码问题一次全通多解法_人工智能八数码-深度学习文档类资源-CSDN下载