过河问题代码学习与总结
- 过河问题代码
- allSubsets()函数说明
- util文件代码
- 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在线性时间内就地转换为堆