您的位置:首页 > 编程语言 > Python开发

十二球称重问题的 Python 程序 bug 修正版

2007-08-27 11:18 363 查看
题目是这样的:
  12个球,其中一个质量和其余的不同,用一个无砝码的天平最多分3次称出。以前考虑过,但最终得出了一个错误的结论。这次应 quanben 之请再想了一下,大致如下解法:

# vim: set sts=4 ts=4 sw=4 et:
# twlvball.py: solves the twelve balls problem.

import sys
import operator

class Ball():
def __init__(self, num, w):
self.num = num
self.weight = w

def main():
print "This program is fragile. Try not to enter wrong arguments."
sys.stdout.write("ball number[0-11]: ")
num = int(sys.stdin.readline().rstrip())
assert 0 <= num and num < 12
sys.stdout.write("weight[h/l]: ")
w = sys.stdin.readline().rstrip()
assert w in ["h", "l"]
test(num, w)

def test(num, w):
balls = []
for i in range(12):
balls.append(Ball(i, 100))
balls[num].weight = (150 if w == "h" else 50)
print solve(balls)

def solve(balls):
# weigh 4 left, 4 right and 4 free.
res0 = weigh(balls[0:4], balls[4:8])
if res0 == 0:
# in 4 free: 8, 9, 10, 11; weigh 1 left, 1 right and 2 free.
if weigh(balls[8:9], balls[9:10]) != 0:
# in 2 weighed; weigh 1 good left and 1 unsure right.
if weigh(balls[0:1], balls[8:9]) != 0:
return 8
else:
return 9
else:
# in 2 free; weigh 1 good left and 1 unsure right.
if weigh(balls[0:1], balls[10:11]) != 0:
return 10
else:
return 11
else:
# in 8 weighed; do a 5-3 split and within the 5, do a 2-1 swap.
# for example, we take 3 from the left and 2 from the right.
# the rest 3 are removed.
# and swap 2 of the left to the right and 1 of the right to the left.
# and then fill each side with good ones.
# the idea is: make them as divided as much, and swapping 3 balls is
# better than swapping 2.
# make the number balanced using good ones.
# [0:1]: one of the left.
# [5:6]: one of the right swapped to the left.
# and plus a good one.
left = concat(balls[0:1], balls[5:6], balls[8:9])
# [4:5]: one of the right.
# [1:3]: two of the left swapped to the right.
right = concat(balls[4:5], balls[1:3])
res1 = weigh(left, right)
if res1 == 0:
# in the rest 3 balls: 3, 6, 7; n6 and n7 were on the right and n3
# were on the left originally in the first weighing.
# take 1 from right to left, and leave 1 from left still left, and
# weigh them against 2 good balls.
# [3:4]: originally left.
# [6:7]: originally right.
left = concat(balls[3:4], balls[6:7])
# take two good balls
right = balls[0:2]
res2 = weigh(left, right)
if res2 == 0:
# ah, the one that is not weighed.
return 7
elif res2 != res0:
# the one moved from right to left
return 6
else:
# the one stayed on the left
return 3
elif res1 == res0:
# among those not swapped: 0, 4; take a good with an unsure.
if weigh(balls[0:1], balls[1:2]) == 0:
# the rest
return 4
else:
return 0
else:
# among the swapped: 1, 2, 5
# leave n5 on the right, and move n1 to the right.
# have 2 good on the left.
left = concat(balls[0:1], balls[3:4])
right = concat(balls[1:2], balls[5:6])
res2 = weigh(left, right)
if res2 == 0:
# the one that is not weighed.
return 2
elif res2 != res0:
# the one moved from left to right
return 1
else:
# the one stayed on the right
return 5

def concat(*lists):
return reduce(operator.add, lists)

def weigh(a, b):
return sum([x.weight for x in a]) - sum([x.weight for x in b])

main()

%%

有关 quanben 的解法请参见他的 blog: http://blog.csdn.net/quanben/archive/2007/08/23/1756706.aspx
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: