12球问题

  12个球,其中一个质量和其余的不同,用一个无砝码的天平最多分3次称出。以前考虑过,但好像最终没得出详细结论,这次再想了一下,大致如下解法:

任取8个,对等称
if 平衡
  异常发生在其余4个,取其中2个置左和2个正常的比较
  if 平衡
    未取出的2个任取1个和正常的比即可知道结果
  else
    取出的2个互比,即可得到结果
  endif
else
  不妨设左边轻,取8个中左右各3个,其中互换1对,
  右边的另某1个用剩余4个(正常)中的1个换出,然后称
  if 平衡
    异常发生在换出者(可能重)或剩余未比较的两者(一个可重,一个可轻)
    将两个“可重”的比较,如平衡,则异常为“可轻”,否则为比较的重者。
  else if 左边轻
    左边原始的2个互称,轻者异常
  else /* 右边轻,反转 */
    互换对中任取一个和正常者互称,即可找出异常
  end if

end if

I have just received from dede an implenentation with some insignifcant difference, which implies that the problem has multiple solutions. We do appreciate the work he finished in python:

# 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())
    sys.stdout.write("weight[h/l]: ")
    w = sys.stdin.readline()
    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()

reference: http://blog.csdn.net/r_mosaic/archive/2007/08/27/1760377.aspx 

posted @ 2007-08-23 22:13  quanben  阅读(193)  评论(0编辑  收藏  举报