泊松分酒

ZZ From:http://www.cnblogs.com/heaad/archive/2010/11/22/1884658.html

有一个12品脱(pint)的酒瓶,里面装满葡萄酒,另有8品脱和5品脱的瓶子各一个。问如何从中分出6品脱的酒出来?

传说泊松年轻时成功解决了该问题,勾起了他对数学的兴趣而投身数学研究,因此该问题被称为泊松分酒问题。另外这个问题又被称为分油问题啦,分水问题啦等等。

小学的时候在一本《十万个问什么——数学卷》中看到过这个问题,那本书直接给出了一个解答过程,又没说原理,看得我糊里糊涂。

一 .  解答过程

为了方便说明,将容量为12品脱,8品脱,5品脱瓶子分别称为大瓶子,中瓶子,小瓶子。按照下面2种规则中的如何一种可以解决这个问题:

第一套规则:

1. 大瓶子只能倒入中瓶子

2. 中瓶子只能倒入小瓶子

3. 小瓶子只能倒入大瓶子

4. 小瓶子只有在已经装满的情况下才能倒入大瓶子

5. 若小瓶子被倒空,则无论中瓶子是否满,应马上从中瓶子倒入小瓶子

之所以要规定倒酒的顺序是为了防止状态重复。而根据这5条规则,大瓶子每次倒入中瓶子的酒总是8品脱,小瓶子每次倒入大瓶子的酒总是5品脱。(请结合下面的表来理解这句话,理解这点很重要)

有了上面的规定后,倒酒的顺序就确定下来了:

12品脱瓶子
8品脱瓶子
5品脱瓶子

12品脱瓶子 8品脱瓶子 5品脱瓶子  
12 0 0 初始状态
4 8(倒进) 0  
4 3 5(倒进)  
9(倒进) 3 0  
9 0 3(倒进)  
1 8(倒进) 3  
1 6 5(倒进) 搞到6品脱了
6 6 0 完成

第二套规则:

1. 大瓶子只能倒入小瓶子

2. 小瓶子只能倒入中瓶子

3. 中瓶子只能倒入大瓶子

4. 中瓶子只有在已经装满的情况下才能倒入大瓶子

5. 若中瓶子被倒空,则无论小瓶子是否满,应马上将小瓶子倒入中瓶子

其实只是将第一套规则中的“中”和“小”两个字对换了一下。

根据这个规则确定的倒酒的顺序如下(注意,我将8品脱和5品脱的位置交换了一下):

12品脱瓶子
5品脱瓶子
8品脱瓶子

12品脱瓶子 5品脱瓶子 8品脱瓶子  
12 0 0 初始状态
7 5(倒进) 0  
7 0 5(倒进)  
2 5(倒进) 5  
2 2 8(倒进)  
10(倒进) 2 0  
10 0 2(倒进)  
5 5(倒进) 2  
5 0 7(倒进)  
0 5(倒进) 7  
0 4 8(倒进)  
8(倒进) 4 0  
8 0 4(倒进)  
3 5(倒进) 4  
3 1 8(倒进)  
11(倒进) 1 0  
11 0 1(倒进)  
6 5(倒进) 1 搞到6品脱了
6 0 6(倒进) 完成

好了试试用这两种规则之一解决如下分酒问题吧:

大瓶子容量10,中瓶子容量7,小瓶子容量3,要分出来5

二.  原理


设大,中,小三个瓶子容量分别是C1,C2,C3,需要倒出的容量是R

则实际上要是我们能将容量为R的酒倒到中瓶子和小瓶子中就可以啦(有点废话)

设大瓶子倒满中瓶子X次,从小瓶子中倒入大瓶子Y次。

那么显然由大瓶子累次倒入中瓶子和小瓶子总共C2*X的酒。而由小瓶子倒入大瓶子一共有C3*Y的酒。

那么最终,小瓶子和中瓶子剩余的酒显然就是 C2*X - C3*Y

因此,泊松分酒问题实质上转化为下面的不定方程是否有正整数解的问题:

C2*X - C3*Y = R

对于我们的问题,

C1=12,C2=8,C3=5,R=6

第一种倒酒规则实质上相当于解下面这个不定方程:

8X - 5Y = 6  ( 限定 X > 0 ,Y > 0 )

最小整数解是 X=2,Y= 2

表示倒满8品脱的瓶子2次,5品脱的瓶子倒空2次

那么8品脱的瓶子和5品脱的瓶子剩酒总量必然是 8 * 2 – 5 * 2 = 6

第二种倒酒规则实质上相当于解下面的不定方程:

5X - 8Y = 6 ( 限定 X > 0 , Y > 0 )

最小整数解是 X = 6 ,Y= 3

表示倒进5品脱瓶子6次,从8品脱瓶子中倒出3次

那么最终5品脱和8品脱的瓶子剩酒总量必然是 5 * 6 – 8 * 3 = 6

好了,现在你明白为什么要规定倒酒的顺序了吧。小瓶子和中瓶子是一个系统,而大瓶子又是另外一个系统,大瓶子的酒只能倒入中瓶子和小瓶子组成的系统,小瓶子的酒只能倒出到大瓶子的系统。我们关注的是由中瓶子和小瓶子组成的系统,这个系统每次增加都是8品脱(中瓶子容量),每次减少都是5品脱(小瓶子容量)。

另外,如果存在X和Y,使得下面的方程有解:

C2*X - C3*Y = 1

实质上就是说能够倒出1品脱的酒,那么任意品脱的酒都能倒出了。

因为:

(C2*X - C3*Y)*N = N

--------------------------------------------------------------------------------------------------

#include <stdio.h>
int i;

void pour(int a,int y,int z)
{
    int b=0,c=0;
    printf("a b c\n%4d%4d%4d\n",a,b,c);
    while (1)
    {
        /*todo*/
    if (a==i || b==i || c==i)
    {
        /*todo*/
        break;
    }

    if (!b)
    {
        /*todo*/
        a-=y;
        b=y;
    }
    else if(c==z)
    {
        a+=z;
        c=0;
    }
    else if(b>z-c)
    {
        b-=(z-c);
        c=z;
    }
    else if(b<=z-c)
    {
        c+=b;
        b=0;
    }
    printf("%4d%4d%4d\n",a,b,c);
    }
}

int main(int argc, char *argv[])
{
    /*todo*/
    int a,y,z;
    printf("Input full a,empty b,c,get i:");
    scanf("%d%d%d%d",&a,&y,&z,&i);
    pour(a,y,z);
    pour(a,y,z);
    return 0;

}
Technorati 标签: C,泊松分酒
posted @ 2010-12-19 00:29  flyfires  阅读(215)  评论(0)    收藏  举报