人工智能 水壶问题 python解法

人工智能 水壶问题 python解法


系列文章

  • 人工智能 倒啤酒问题 python解法
  • 人工智能 水壶问题 python解法
  • A*算法之八数码问题 python解法
  • A*算法之野人传教士问题 python解法
  • 人工智能 遗传算法 计算函数极值问题

文章目录

  • 人工智能 水壶问题 python解法
    • 问题描述
    • 宽度优先搜索
    • 状态空间
    • 操作类型
    • 思路
    • 代码


补充发两篇文章记录一下之前用到的宽度优先算法

问题描述

给定两个水壶,一个可以装4升水,一个能装3升水,水壶上没有任何度量标记。有一水龙头可以用来往壶中灌水。问题是怎样在能装4升的水壶里面恰好只装2升水。

人工智能 水壶问题 python解法_第1张图片
问题不难理解,就是倒水,倒来倒去然后一个杯子里只剩2升水了

宽度优先搜索

  1. 把起始点放入queue;
  2. 重复下述2步骤,直到queue为空为止:
    1 . 从queue中取出队列头的点;
    2 . 找出与此点邻接的且尚未遍历的点,进行标记,然后全部放入queue中。

可以看看这篇文章,类似关于算法的介绍网上很多
人工智能 水壶问题 python解法_第2张图片
人工智能 水壶问题 python解法_第3张图片
人工智能 水壶问题 python解法_第4张图片
人工智能 水壶问题 python解法_第5张图片
人工智能 水壶问题 python解法_第6张图片
人工智能 水壶问题 python解法_第7张图片

状态空间

(x,y)

  • x代表3升水壶当前的水量,范围(0,1,2,3)
  • y代表4升水壶当前的水量,范围(0,1,2,3,4)。
  • 初值(0,0),目标值(2,?)或者(?,2)

操作类型

本道题的操作也不难,倒来倒去也就这么几种

  1. 装满4升水壶
  2. 装满3升水壶
  3. 清空4升水壶
  4. 清空3升水壶
  5. 3升水壶往4升到 (4升倒满或3升清空)
  6. 4升水壶往3升到 (3升倒满或4升清空)

思路

将各个属性放到一个类中,初始化状态空间,置为全0,仅仅(0,0)点为1,作为是否访问过的依据,再初始化一个队列来存放需要访问的节点,在类中编写操作相关的6个函数,接着使用宽度优先搜索算法进行循环,为了能够获取出正确并且多组路径,在每个节点的内容中添加了其父节点的信息。最后根据这些信息还原出所有的有效路径,这里稍微做出的改进是当遇到目标值后就不再对当前节点继续深入。

代码

人工智能 水壶问题 python解法_第8张图片

# -*- coding: utf-8 -*-
# @Time    : 2020/10/15 19:12
# @Author  : Tong Tianyu
# @File    : chapter1_1.py
import queue
import numpy as np


# 定义水壶类对象
class Kettle:
    def __init__(self):
        self.x = 0  # 三升的水壶
        self.y = 0  # 四升的水壶
        self.state_space = np.zeros((4, 5))  # 定义状态空间
        self.q_tmp = queue.Queue()  # 定义队列
        self.final = []  # 定义结果
        self.final_only_data = [[0, 0]]  # 便于操作的结果

    def BFS(self):
        # con = 1
        self.q_tmp.put([0, 0])
        self.final.append([[0, 0], 'none', [0]])
        self.state_space[0][0] = 1
        while len(self.q_tmp.queue) != 0:
            a, b = self.q_tmp.get()
            if a == 2 or b == 2:
                continue
            pre = [a, b]
            # print('----------------', con, '------------------')
            self.x, self.y = a, b
            self.Pour_X()
            self.update(pre, a, b, 'Pour_X')

            self.Pour_Y()
            self.update(pre, a, b, 'Pour_Y')

            self.Empty_X()
            self.update(pre, a, b, 'Empty_X')

            self.Empty_Y()
            self.update(pre, a, b, 'Empty_Y')

            self.Pour_X_To_Y()
            self.update(pre, a, b, 'Pour_X_To_Y')

            self.Pour_Y_To_X()
            self.update(pre, a, b, 'Pour_Y_To_X')

            # con += 1
        return self.final, self.final_only_data

    def update(self, pre, a, b, name):
        if self.state_space[self.x][self.y] == 0:
            self.state_space[self.x][self.y] = 1
            self.q_tmp.put([self.x, self.y])
            self.final_only_data.append([self.x, self.y])
            self.final.append([[self.x, self.y], name, pre])
        self.x, self.y = a, b

    def Pour_X(self):
        '''倒满三升的水壶X'''
        self.x = 3
        return True

    def Pour_Y(self):
        '''倒满四升的水壶Y'''
        self.y = 4
        return True

    def Empty_X(self):
        '''清空三升的水壶X'''
        self.x = 0
        return True

    def Empty_Y(self):
        '''清空四升的水壶Y'''
        self.y = 0
        return True

    def Pour_X_To_Y(self):
        '''三升的水壶x倒入四升y中'''
        if (self.x + self.y) <= 4:  # 可以完全倒入四升水壶Y中
            self.y = self.x + self.y
            self.x = 0
        else:  # 倒满四升壶y之后还有余量
            self.x = self.x - (4 - self.y)
            self.y = 4
        return True

    def Pour_Y_To_X(self):
        '''四升水壶y倒入三升水壶x中'''
        if (self.x + self.y) <= 3:  # 可以完全倒入三升水壶x中
            self.x = self.x + self.y
            self.y = 0
        else:  # 倒满四升壶y之后还有余量
            self.y = self.y - (3 - self.x)
            self.x = 3
        return True


if __name__ == '__main__':
    kettle = Kettle()
    final_list, tmp_list = kettle.BFS()
    result = []
    for i in range(len(final_list)):
        if i == 0:
            continue
        data = final_list[i]
        print('每行的数据为:', data)
        pre = data[2]
        print('当前的父节点为:', pre)
        pre_index = tmp_list.index(pre)
        print('当前父节点在列表中的位置为:', pre_index)
        result = final_list[pre_index][-1]
        print('当前父节点的路径为:', result)
        # md这里被深浅复制搞死了
        a = result.copy()
        a.append(i)
        final_list[i][-1] = a
        print('*********************************************')


    def output(order):
        print('x' + '\t' + 'y' + '\t' + 'method')
        for i in order:
            print(*final_list[i][0], sep='\t', end='\t')
            print(final_list[i][1])


    con = 0
    for i in range(len(tmp_list)):
        if 2 in tmp_list[i]:
            print(f'-------------方法{con}--------------')
            order = final_list[i][-1]
            output(order)
            con += 1

你可能感兴趣的:(#,人工智能基础,人工智能)