过河问题代码学习与总结

  1. 过河问题代码
  2. allSubsets()函数说明
  3. util文件代码
  4. heapq的简单学习和示例代码

过河问题源代码:

import util
# 返回一个集合的所有小于limit的子集:s=(1,4), return [(1,4),(1),(4),()]
def allSubsets(s, limit):
    if len(s) == 0 or limit == 0:#递归结束的条件,在len(s) == 0 or limit == 0
        return [[]]
    return [[s[0]] + r for r in allSubsets(s[1:], limit-1)] + allSubsets(s[1:], limit) #使用递归的方法求解

class CrossRiverProblem:
    # what is a state e.g. ((1,1,1,1,1), 0),((0,1,1,0,1), 0),前面表示动物,后面表示人。
    # state 状态
    #N表示一共有多少个动物,S表示一个船一次载多少动物
    def __init__(self, N, S):
        self.N = N #N=5
        self.S = S #S=2

    # Return start state ((0,0,0,.....,0),0)
    def startState(self):
        return (tuple(0 for _ in range(self.N)), 0)#返回一个tuple,

    # Return TRUE if state is a goal state ((1,1,.....,1),1)
    def isEnd(self, state):
        return state == ((tuple(1 for _ in range(self.N))), 1)
    # Return a list of successor states and costs
    # (后继节点和代价 of state)
    def succAndCost(self, state):
        print("expand: " + str(state))
        animals = state[0]
        ship = state[1]
        result = []
        #判断在船上的小动物,当小动物在船上的时候,小动物的状态和人的状态是一样的,所以可以用animals[i] == ship 表示。
        # i 表示的是小动物的索引,这样就知道了这个动物是哪一个动物。
        # s 是在船上的动物的所有组合的表示。
        for s in allSubsets([i for i in range(self.N) if animals[i] == ship], self.S):
            temp = list(animals)#tuple转变为list的可以修改形式。
            for i in s:
                temp[i] = 1-ship  #在船的状态再次发生变化的时候,将携带的动物的状态也发生改变。

            newState = (tuple(temp), 1-ship)
            if self.isValidState(newState):#判断新的状态是不是满足条件。
                result.append((newState, 1))#这个1 是cost,
        return result #返回所有后继节点和cost

    def isValidState(self, state):
        animals = state[0]
        ship = state[1]
        for i in range(self.N - 1):
            if animals[i] != ship and animals[i+1] != ship:  #认为连续的两个动物和船的状态不一样是不满足条件的。
                return False
        return True

# 等代价搜索
# (TotalCost of optimal solution, history of solution)
def uniformCostSearch(problem):
    state = problem.startState()
    open = util.PriorityQueue()  #创建一个priorityQueue()类的实例。
    open.update(state, 0)
    while True:
        state, pastCost = open.removeMin()
        if problem.isEnd(state):  #出open表的时候,看一下是不是满足条件。
            print("Total cost: " + str(pastCost))
            return pastCost, []
        for newState, cost in problem.succAndCost(state):
            open.update(newState, pastCost + cost)


problem = CrossRiverProblem(N=5, S=2)  #创建一个类的实例并且初始化。
print(uniformCostSearch(problem))



def AstarSearch(problem, h):
    state = problem.startState()
    open = util.PriorityQueue()
    open.update(state, h(state))
    costs = {state: 0}
    parents = {state: None}
    while True:
        state, pastCost = open.removeMin()
        if problem.isEnd(state):
            print("Total cost: " + str(pastCost - h(state)))
            history = []
            track = state
            while track:
                history.append(track)
                track = parents[track]
            return pastCost, history
        for newState, cost in problem.succAndCost(state):
            open.update(newState, pastCost + cost - h(state) + h(newState))
            if newState not in costs or costs[newState] > pastCost + cost:
                costs[newState] = pastCost + cost
                parents[newState] = state

def printSolution(solution):
    history = solution[1]
    for s in history:
        print(s)

printSolution(AstarSearch(problem, lambda x: 0))

allSubsets()函数说明:

allSubsets()函数使用了递归的写法,基本的思路是,求解一个集合的子集的时候,首先我们把这个集合划分为两个部分,一部分是这个集合的第一个元素,一部分是这个集合除了
第一个元素的后面的元素,然后我们让第一个元素和后面的元素组合求解集合的子集,再在后面的集合里面使用同样的方法求解这个集合的子集,之后将两部分的结果汇总成一部分,
放在一个list里面。这个函数还加了一些限制,我们使用limits变量控制奇求解的集合的长度,这个判断标准就是放在了递归出口的地方。也作为程序的出口。

util文件代码源代码:

import heapq, collections, re, sys, time, os, random
# Data structure for supporting uniform cost search.
class PriorityQueue:
    def  __init__(self):
        self.DONE = -100000
        self.heap = []
        self.priorities = {}  # Map from state to priority
    # Insert |state| into the heap with priority |newPriority| if
    # |state| isn't in the heap or |newPriority| is smaller than the existing
    # priority.
    # Return whether the priority queue was updated.
    def update(self, state, newPriority):
        oldPriority = self.priorities.get(state)
        if oldPriority == None or newPriority < oldPriority:
            self.priorities[state] = newPriority
            heapq.heappush(self.heap, (newPriority, state))
            return True
        return False

    # Returns (state with minimum priority, priority)
    # or (None, None) if the priority queue is empty.
    def removeMin(self):
        while len(self.heap) > 0:
            priority, state = heapq.heappop(self.heap)
            if self.priorities[state] == self.DONE: continue  # Outdated priority, skip
            self.priorities[state] = self.DONE
            return (state, priority)
        return (None, None) # Nothing left...

heapq的学习

import heapq
def heapsort(iterable):
    h  = []
    for value in iterable:
        heapq.heappush(h,value)
    print(heapq.heappop(h))  # -2
    print(heapq.heappushpop(h,-1))  #- 1
    print(heapq.heapreplace(h,10))  # 1
iterable = [1,3,5,7,9,2,4,6,8,-2]
heapsort(iterable)
h = [1,3,5,7,9,2,4,6,8,-2]
heapq.heapify(h)
h #变成堆的结果[2, 1, 2, 6, 3, 5, 4, 7, 8, 9]

heapq是python中的堆队列算法模块,也称为优先级队列算法模块,详细的学习文档请点击python标准库学习。
heapq的基本功能:
heapq.heappush(堆,项目) 将值推入堆中,保持堆不变。
heapq.heappop(堆) 弹出并从堆中返回最小的顶,从而保持堆不变,要访问最小的项目但是不弹出,可以使用heap[0]
heapq.heappushpop(堆,项目)将项目推入堆中,然后弹出并从堆中返回最小的项目
heapq.heapify(x) 将列表X在线性时间内就地转换为堆

posted on 2020-04-10 16:14  zzcf  阅读(454)  评论(0编辑  收藏  举报