小孩分油问题

1.问题描述

两个小孩去打油,一人带了一个一斤的空瓶,另一个带了一个七两、一个三两的空瓶。原计划各打一斤油,可是由于所带的钱不够,只好两人合打了一斤油,在回家的路上,两人想平分这一斤油,可是又没有其它工具,试仅用三个瓶子(一斤、七两、三两)精确地分成两个半斤油来。

 

2.算法设计

假设状态A(x1,x2,x3)表示依次表示一斤,七两,三两瓶子中含油量为x1,x2,x3

状态A的下一个状态B的转换:

每一个瓶子含油量为0则不变。如果含油量不为0则可以选择向其他两个瓶子倒油,倒油的情况又可以分为两种:1.当前瓶子剩余油量不够倒满其他某个瓶子;2.当前瓶子剩余油量足够倒满其他的某个瓶子

 

3.程序流程

1.将初始状态S(10,0,0)加入到队列之中。

2.从队列中取出队首元素对应的状态A,状态A进行宽度优先搜索,状态A扩充得到的状态B,如果状态B即为目标状态(5,5,0)侧退出搜索,转到步骤5。

3.判断状态B是否在队列中,不在的话就添加至队列末尾,并且记录下状态B的前一个状态为状态A,方便找到目标状态之后寻找解的路径。已经在队列中的话侧跳过

4.用状态A搜索完所有的下一个状态之后,状态A出队,判断队列是否为空,为空的话就停止搜索,宣告搜索失败;队列不为空的话就转到步骤2

5.搜索过程中记录了每个状态的前一个状态,所以可以利用目标状态输出整个搜索路径。

4.代码实现

import copy

class path(object):
    def __init__(self, p, pre=-1):
        self.p = p #当前状态
        self.pre = pre #前一步

def pour(i, j, p): #倒油处理
    if p[i] >= (cap[j]-p[j]): #当前瓶子剩余油量足够倒满其他的某个瓶子
        p[i] = p[i]-(cap[j]-p[j])
        p[j] = cap[j]
    else: #当前瓶子剩余油量不够倒满其他某个瓶子
        p[j] += p[i]
        p[i] = 0

def bfs(start, que):
    front, tail = 0, 0
    que[tail] = start
    # que[tail].p = start.p
    # que[tail].pre = start.pre
    tail += 1
    book[start.p[0]*100 + start.p[1]*10 + start.p[2]] = 1 #避免出现重复的状态

    while front <= tail:
        node = que[front]

        for i in range(0, 3):
            if node.p[i] != 0:
                for j in range(1, 3):
                    temp = copy.deepcopy(node.p)
                    pour(i, (i+j)%3, temp)
                    if (temp[0]==5 and temp[1]==5):
                        que[tail].p = temp
                        que[tail].pre = front
                        output(que[tail])
                        print("")
                        # return tail
                    if book[temp[0] * 100 + temp[1]*10 + temp[2]]:
                        continue
                    book[temp[0] * 100 + temp[1]*10 + temp[2]] = 1
                    que[tail].p = temp
                    que[tail].pre = front
                    tail += 1
        front += 1

def output(node):
    if node.pre == -1:
        print(node.p)
        return
    output(que[node.pre])
    print(node.p)

start = path([10, 0, 0], -1)
cap = [10, 7, 3]
que = [path(None) for i in range(100)] #假设最多一百步
book = [0]*100000

end = bfs(start, que)
# output(que[end])

6.结论

油瓶分油问题借助广度优先搜索树可以得到较好的解决。只要问题有解,广度优先搜索一定能在有限步内找到解且路径最短。但是随着深度的增加,结点数目指数增长,导致组合爆炸。导致空间占用爆炸。最后是可以利用启发式搜索效率会更高一些。

猜你喜欢

转载自blog.csdn.net/breeze_blows/article/details/102992617