小孩分油问题:
两个小孩去打油,一人带了一个一斤的空瓶,另一个带了一个七两、一个三两的空瓶。原计划各打一斤油,可是由于所带的钱不够,只好两人合打了一斤油,在回家的路上,两人想平分这一斤油,可是又没有其它工具。试仅用三个瓶子(一斤、七两、三两)精确地分出两个半斤油来。
说明:
一斤 = 10两;
算法设计:
设置三个油瓶分别为A, B, C,初始化三个油瓶的初始状态(10,0,0),满油状态(10,7,3),目标状态(5,5,0)。使用广度优先的搜索方法,对每一种可能情况进行遍历,最终取得结果。其中,对于每一种情况对应每一步操作,操作需要满足一定的约束条件:把A瓶中的油全部倒入B瓶或者把A瓶中的油部分倒入B瓶使B瓶满油。
广度搜索 (BFS)代码实现:
from collections import deque
def nextStep(current_state, oil_volume):
next_actions = [
(from_, to_)
for from_ in range(3) for to_ in range(3)
if from_ != to_ and current_state[from_] > 0 and current_state[to_] < oil_volume[to_]
]
for from_, to_ in next_actions:
next_state = list(current_state)
transfer_amount = min(current_state[from_], oil_volume[to_] - current_state[to_])
next_state[from_] -= transfer_amount
next_state[to_] += transfer_amount
yield next_state
def depthFirstSearch(record, oil_volume=[10, 7, 3], final_state=[5, 5, 0]):
global num, record_list
current_state = record[-1]
if current_state == final_state:
num += 1
record_list.append(deque(record))
print(f"方法{num}: {'->'.join(map(str, record))}")
return
next_stages = nextStep(current_state, oil_volume)
for stage in next_stages:
if stage not in record:
record.append(stage)
depthFirstSearch(record, oil_volume, final_state)
record.pop()
if __name__ == '__main__':
initial_oil_state = [10, 0, 0]
num = 0
record_list = []
record = deque()
record.append(initial_oil_state)
depthFirstSearch(record)
number = f"深度优先搜索共有{num}种方法"
shortest = f"路径最短的方法中操作步总数为{min(len(i) for i in record_list)}"
print(number)
print(shortest)
from collections import deque
def nextStep(current_state, oil_volume):
next_actions = [
(from_, to_)
for from_ in range(3) for to_ in range(3)
if from_ != to_ and current_state[from_] > 0 and current_state[to_] < oil_volume[to_]
]
for from_, to_ in next_actions:
next_state = list(current_state)
transfer_amount = min(current_state[from_], oil_volume[to_] - current_state[to_])
next_state[from_] -= transfer_amount
next_state[to_] += transfer_amount
yield next_state
def searchResult(record, oil_volume=[10, 7, 3], final_state=[5, 5, 0]):
global num, record_list
current_state = record[-1]
next_stages = nextStep(current_state, oil_volume)
for stage in next_stages:
if stage not in record:
record.append(stage)
if stage == final_state:
num += 1
record_list.append(deque(record))
print(f"方法{num}: {'->'.join(map(str, record))}")
else:
searchResult(record, oil_volume, final_state)
record.pop()
if __name__ == '__main__':
initial_oil_state = [10, 0, 0]
num = 0
record_list = []
record = deque()
record.append(initial_oil_state)
searchResult(record)
number = f"广度优先搜索共有{num}种方法"
shortest = f"路径最短的方法中操作步总数为{min(len(i) for i in record_list)}"
print(number)
print(shortest)
代码结果
结论:
由代码运行结果可知:整棵树一共有20种方法能够达到要求,其中最佳即路径最短的方法为第9种方法。
第9种方法:[10, 0, 0]->[3, 7, 0]->[3, 4, 3]->[6, 4, 0]->[6, 1, 3]->[9, 1, 0]->[9, 0, 1]->[2, 7, 1]->[2, 5, 3]->[5, 5, 0]
具体做法为:
0) 初始化–>[10, 0, 0]
- A瓶倒满B瓶–>[3, 7, 0]
- B瓶倒满C瓶–>[3, 4, 3]
- C瓶倒满A瓶–>[6, 4, 0]
- B瓶倒满C瓶–>[6, 1, 3]
- C瓶倒满A瓶–>[9, 1, 0]
- B瓶倒满C瓶–>[9, 0, 1]
- A瓶倒满B瓶–>[2, 7, 1]
- B瓶倒满C瓶–>[2, 5, 3]
- C瓶倒满A瓶–>[5, 5, 0]
深度优先搜索 (DFS):从起始节点出发,尽可能深入到图的最深层,然后再回溯,继续深入到下一个分支。它使用堆栈(递归或显式堆栈)来维护节点的访问顺序。广度优先搜索 (BFS):从起始节点开始,首先访问其所有的相邻节点,然后逐层地向外扩展,直到找到目标节点或遍历完整个图。它使用队列来维护节点的访问顺序。遍历顺序:DFS 通常倾向于深度遍历,即沿着一条路径尽可能深入,然后回溯到上一个分支。这可能导致较长的路径被首先探索。BFS 倾向于逐层遍历,首先探索距离起始节点最近的节点,然后逐渐向外扩展。这通常导致找到的路径较短。数据结构:DFS 使用堆栈(递归或显式堆栈)来维护节点的访问顺序。BFS 使用队列来维护节点的访问顺序。相似之处:应用领域:DFS和BFS都可以用于解决各种问题,包括图遍历、路径查找、状态空间搜索、拓扑排序等。完备性:如果问题有解,DFS和BFS都能找到解,但不一定是最优解。DFS可能找到的不是最短路径,而BFS通常能找到最短路径。时间复杂度:在最坏情况下,DFS和BFS的时间复杂度都可以达到O(V + E),其中V是节点数,E是边数。但在实际应用中,它们的性能可能会有所不同,取决于问题的性质和图的结构。空间复杂度:DFS通常需要较少的空间,因为它只需要维护一个栈,而BFS需要维护一个队列,可能需要更多的内存空间。总之,DFS和BFS是两种不同的搜索策略,各自适用于不同的问题和场景。DFS适用于深度搜索,通常用于找到解的问题。BFS适用于广度搜索,通常用于找到最短路径或最短步数的问题。选择哪种算法取决于具体问题的需求和图的结构。