这个题目的版本非常之多,有微软版的,腾讯版的,新浪版的等等,最常见的是:
有容量为a,b的2个水桶,需要得到c升的水.
UPDATE:
1.重新实现了方案b,要么a->b不停的倒,要么b->a不停的倒,直到目标出现或者水量重复(无解).
2.比较两种方案可以获得最佳方案.
3.根据checkio题目要求,输出倒水步骤:01表示填满a,12表示从a倒入b,20表示倒空b.(0,水源,1,第一个水桶,2,第二个水桶)
def checkio(a,b,c): print '------------------------------------------------' print '[A=%d] [B=%d] [C=%d] (target is C)' % (a,b,c) history = [] # pour history wlist = [(0,0)] # water of a,b # a->b repeadily while 1: # full a if wlist[-1][0]==0: wlist.append((a,wlist[-1][1])) history.append('01') if c in wlist[-1] or wlist[-1] in wlist[:-1]: break # empty b if wlist[-1][1]==b: wlist.append((wlist[-1][0],0)) history.append('20') if c in wlist[-1] or wlist[-1] in wlist[:-1]: break # a->b if sum(wlist[-1])<=b: wlist.append((0,sum(wlist[-1]))) else: wlist.append((sum(wlist[-1])-b,b)) history.append('12') if c in wlist[-1] or wlist[-1] in wlist[:-1]: break print 'A->B:',wlist list1 = [] # solution1 hist1 = [] if c in wlist[-1]: # found solution list1 = wlist[:] hist1 = history[:] else: # no solution list1 = [] hist1 = [] # exchange a,b history = [] wlist = [(0,0)] # b->a repeadily while 1: # full b if wlist[-1][1]==0: wlist.append((wlist[-1][0],b)) history.append('02') if c in wlist[-1] or wlist[-1] in wlist[:-1]: break # empty a if wlist[-1][0]==a: wlist.append((0,wlist[-1][1])) history.append('10') if c in wlist[-1] or wlist[-1] in wlist[:-1]: break # b->a if sum(wlist[-1])<=a: wlist.append((sum(wlist[-1]),0)) else: wlist.append((a,sum(wlist[-1])-a)) history.append('21') if c in wlist[-1] or wlist[-1] in wlist[:-1]: break print 'B->A:',wlist list2 = [] # solution2 hist2 = [] if c in wlist[-1]: # found solution list2 = wlist[:] hist2 = history[:] else: list2 = [] hist2 = [] # compare the solutions to have minimal steps result = [] if not list1 and not list2: result = [] print 'No solution' return result elif not list1: wlist = list2 result = hist2 elif not list2: wlist = list1 result = hist1 else: wlist = len(list1)<len(list2) and list1 or list2 result = len(list1)<len(list2) and hist1 or hist2 # print the result for item in wlist[1:]: print item[0],item[1] # return the result print 'Optimal solution:',wlist print 'Done' print '------------------------------------------------' return result #These "asserts" using only for self-checking and not necessary for auto-testing if __name__ == '__main__': print(checkio(5, 7, 6)) # ['02', '21', '10', '21', '02', '21', '10', '21', '02', '21'] print(checkio(3, 4, 1)) # ["02", "21"] print(checkio(2, 1, 1)) # ["02"] print(checkio(2, 7, 1))结果:
>>> ================================ RESTART ================================ >>> ------------------------------------------------ [A=5] [B=7] [C=6] (target is C) A->B: [(0, 0), (5, 0), (0, 5), (5, 5), (3, 7), (3, 0), (0, 3), (5, 3), (1, 7), (1, 0), (0, 1), (5, 1), (0, 6)] B->A: [(0, 0), (0, 7), (5, 2), (0, 2), (2, 0), (2, 7), (5, 4), (0, 4), (4, 0), (4, 7), (5, 6)] 0 7 5 2 0 2 2 0 2 7 5 4 0 4 4 0 4 7 5 6 Optimal solution: [(0, 0), (0, 7), (5, 2), (0, 2), (2, 0), (2, 7), (5, 4), (0, 4), (4, 0), (4, 7), (5, 6)] Done ------------------------------------------------ ['02', '21', '10', '21', '02', '21', '10', '21', '02', '21'] ------------------------------------------------ [A=3] [B=4] [C=1] (target is C) A->B: [(0, 0), (3, 0), (0, 3), (3, 3), (2, 4), (2, 0), (0, 2), (3, 2), (1, 4)] B->A: [(0, 0), (0, 4), (3, 1)] 0 4 3 1 Optimal solution: [(0, 0), (0, 4), (3, 1)] Done ------------------------------------------------ ['02', '21'] ------------------------------------------------ [A=2] [B=1] [C=1] (target is C) A->B: [(0, 0), (2, 0), (1, 1)] B->A: [(0, 0), (0, 1)] 0 1 Optimal solution: [(0, 0), (0, 1)] Done ------------------------------------------------ ['02'] ------------------------------------------------ [A=2] [B=7] [C=1] (target is C) A->B: [(0, 0), (2, 0), (0, 2), (2, 2), (0, 4), (2, 4), (0, 6), (2, 6), (1, 7)] B->A: [(0, 0), (0, 7), (2, 5), (0, 5), (2, 3), (0, 3), (2, 1)] 0 7 2 5 0 5 2 3 0 3 2 1 Optimal solution: [(0, 0), (0, 7), (2, 5), (0, 5), (2, 3), (0, 3), (2, 1)] Done ------------------------------------------------ ['02', '21', '10', '21', '10', '21'] >>>
解法肯定有很多,可以用宽度优先搜索(BFS),也可以用穷举法。
这里列2个很有意思的解决方案,第一个很巧妙,可以手动解决,第二个则是终极(不一定是最优)解决办法,特别适合计算机完成.
# 解决思路:
# a,有限状态机 ,可以画图解决
# http://www.cnblogs.com/wisdomqq/archive/2009/09/22/1571520.html
# b,不断取余,不一定是最优解. 基本思想是用:用一个桶容量的倍数对另一个桶的容量取余。
# http://blog.csdn.net/morewindows/article/details/7481851
方案B的实现代码:
#! /usr/bin/env python # coding=utf-8 # 倒水问题, 有容量为a,b的2个水桶,需要得到c升的水 # 解决思路: # a,有限状态机 ,可以画图解决 # http://www.cnblogs.com/wisdomqq/archive/2009/09/22/1571520.html # b,不断取余,不一定是最优解 # http://blog.csdn.net/morewindows/article/details/7481851 # 使用b方法,不停取余 def solve_2(a,b,c): wlist = [(0,0)] # 水量 qlist = [] # 余数列表,如果不管怎么倒都循环,无解决方案 t = a # a的倍数 while 1: # 装满A wlist.append((a,wlist[-1][1])) # A倒入B if sum(wlist[-1])<=b: wlist.append((0,wlist[-1][0]+wlist[-1][1])) else: wlist.append((sum(wlist[-1])-b,b)) if t%b in qlist: break else: qlist.append(t%b) # 倒空B后A倒入B if wlist[-1][1]==b: wlist.append((wlist[-1][0],0)) wlist.append((0,wlist[-1][0])) # 判断余数是否循环 if t%b==c: break t += a # 无方案,交换a,b再来一次 if c not in wlist[-1]: wlist = [(0,0)] qlist = [] a,b = b,a t = a while 1: # 装满A wlist.append((a,wlist[-1][1])) # A倒入B if sum(wlist[-1])<=b: wlist.append((0,wlist[-1][0]+wlist[-1][1])) else: wlist.append((sum(wlist[-1])-b,b)) if t%b in qlist: break else: qlist.append(t%b) # 倒空B后A倒入B if wlist[-1][1]==b: wlist.append((wlist[-1][0],0)) wlist.append((0,wlist[-1][0])) # 判断余数是否循环 if t%b==c: break t += a # 交换后还是无法解决 if c not in wlist[-1]: print '[A=%d] [B=%d] [C=%d] (target is C)' % (b,a,c) print 'No possible solution' else: print '[A=%d] [B=%d] [C=%d] (target is C)' % (b,a,c) print '------------------------------------------------' print 'One possible solution is (not necessaryly to be optimal):' for item in wlist[1:]: if item[0]==a: print '%8s A : %d B : %d' % ('Full B',item[1],item[0]) elif item[0]<a and item[1]!=0: print '%8s A : %d B : %d' % ('B -> A',item[1],item[0]) elif item[1]==0: print '%8s A : %d B : %d' % ('Empty A',item[1],item[0]) print 'Done' print '------------------------------------------------' else: print '[A=%d] [B=%d] [C=%d] (target is C)' % (a,b,c) print '------------------------------------------------' print 'One possible solution is (not necessary to be optimal):' for item in wlist[1:]: if item[0]==a: print '%8s A : %d B : %d' % ('Full A',item[0],item[1]) elif item[0]<a and item[1]!=0: print '%8s A : %d B : %d' % ('A -> B',item[0],item[1]) elif item[1]==0: print '%8s A : %d B : %d' % ('Empty B',item[0],item[1]) print 'Done' print '------------------------------------------------' def main(): solve_2(5,8,6) if __name__ == '__main__': main()测试结果:
>>> ================================ RESTART ================================ >>> [A=5] [B=8] [C=6] (target is C) ------------------------------------------------ One possible solution is (not necessary to be optimal): Full A A : 5 B : 0 A -> B A : 0 B : 5 Full A A : 5 B : 5 A -> B A : 2 B : 8 Empty B A : 2 B : 0 A -> B A : 0 B : 2 Full A A : 5 B : 2 A -> B A : 0 B : 7 Full A A : 5 B : 7 A -> B A : 4 B : 8 Empty B A : 4 B : 0 A -> B A : 0 B : 4 Full A A : 5 B : 4 A -> B A : 1 B : 8 Empty B A : 1 B : 0 A -> B A : 0 B : 1 Full A A : 5 B : 1 A -> B A : 0 B : 6 Done ------------------------------------------------
No comments :
Post a Comment