小孩分油问题 (附python代码)

小孩分油问题

题目:

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

算法设计

设置三个油瓶分别为A, B, C,初始化三个油瓶的初始状态(10,0,0),满油状态(10,7,3),目标状态(5,5,0)。使用广度优先的搜索方法,对每一种可能情况进行遍历,最终取得结果。其中,对于每一种情况对应每一步操作,操作需要满足一定的约束条件:把A瓶中的油全部倒入B瓶或者把A瓶中的油部分倒入B瓶使B瓶满油。具体的约束条件见程序流程。本算法由python实现。

程序流程

1.png
序号 规则 解释
1 (B,C) and B<7 -> (7,C) B瓶不满的时候装满
2 (B,C) and C<3 -> (B,3) C瓶不满的时候装满
3 (B,C) and B>0 -> (0,C) B瓶不满的时候装满
4 (B,C) and C>0 -> (B,0) C瓶不满的时候装满
5 (B,C) and B>0 and B+C<=3 -> (0,B+C) B瓶的油全倒入C瓶
6 (B,C) and C>0 and B+C<=7 -> (B+C,0) C瓶的油全倒入B瓶
7 (B,C) and B>0 and B+C>=3 -> (B+C-3,3) B瓶的油全倒入C瓶
8 (B,C) and C>0 and B+C>=7 -> (7,B+C-7) C瓶的油全倒入B瓶
1.png

核心伪代码

Def 下一步:
下一个操作 = [
        (倒出瓶标签, 倒入瓶标签)
        for 倒出瓶标签 range(3) for 倒入瓶标签 in range(3)
if 倒入/出瓶标签不能相同 and 倒出的瓶不为空 and 已经满了的瓶不能再倒入    ]

    for 倒出瓶标签, 倒入瓶标签 in 下一步操作:
        if 倒出倒入瓶由量之后不超过倒入瓶最大容量
            倒出瓶油量 -= (倒入瓶最大容量-倒入瓶现有油量)
            倒入瓶油量 = 倒入瓶最大容量
        else:
            倒出瓶油量 = 0
            倒入瓶油量 = 倒入瓶现有油量 + 倒出瓶现有油量
        yield 下一步

Def 搜索结果:
for 操作in 下一步:
        if 没有试过该操作:
            将该操作加入队列
            if 当前结果== 目标结果:
              输出结果
            else:
                递归本函数‘搜索结果’
            删除队列最后一个

代码运行及测试:

·.png

结论

由代码运行结果可知:整棵树一共有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]
​ 1) A瓶倒满B瓶-->[3, 7, 0]
​ 2) B瓶倒满C瓶-->[3, 4, 3]
​ 3) C瓶倒满A瓶-->[6, 4, 0]
​ 4) B瓶倒满C瓶-->[6, 1, 3]
​ 5) C瓶倒满A瓶-->[9, 1, 0]
​ 6) B瓶倒满C瓶-->[9, 0, 1]
​ 7) A瓶倒满B瓶-->[2, 7, 1]
​ 8) B瓶倒满C瓶-->[2, 5, 3]
​ 9) C瓶倒满A瓶-->[5, 5, 0]

源代码:

'''
@author: 嘿芝麻

@software: garner
@file: main_oil.py
@time: 2018/10/5
'''
from collections import deque

def nextStep(current_state, oil_volume):
    next_action = [
        (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_action:
        next_state = list(current_state)
        if current_state[from_] + current_state[to_] > oil_volume[to_]:
            next_state[from_] -= (oil_volume[to_] - current_state[to_])
            next_state[to_] = oil_volume[to_]
        else:
            next_state[from_] = 0
            next_state[to_] = current_state[to_] + current_state[from_]
        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_stage = nextStep(current_state, oil_volume)

    for stage in next_stage:
        if stage not in record:
            record.append(stage)
            if stage == final_state:
                numm = num + 1
                s_numm = str(numm)
                str_record = ''
                for i in record:
                    str_record += str(i)
                    if i != [5, 5, 0]:
                        str_record += '->'
                print("方法{}:{}".format(s_numm, str_record))
                record_list.append(deque(record))
                num += 1
            else:
                searchResult(record, oil_volume, final_state)
            record.pop()


if __name__ == '__main__':
    initial_oil_state = [10, 0, 0]
    oil_volume = [10, 7, 3]
    num = 0
    record_list = []
    record = deque()
    record.append(initial_oil_state)
    searchResult(record)
    number = "广度优先搜索共有{}种方法".format(num)
    shortest = "路径最短的方法中操作步总数为{}".format(min([len(i) for i in record_list]))

    print(number)
    print(shortest)


最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 217,277评论 6 503
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 92,689评论 3 393
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 163,624评论 0 353
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 58,356评论 1 293
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 67,402评论 6 392
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,292评论 1 301
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,135评论 3 418
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,992评论 0 275
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,429评论 1 314
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,636评论 3 334
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,785评论 1 348
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,492评论 5 345
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 41,092评论 3 328
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,723评论 0 22
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,858评论 1 269
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,891评论 2 370
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,713评论 2 354