水杯题的非常好的解释

两次被问到这题了一次谷歌,一次百度,有必要好好弄清楚。

先看这个题目,再看这个题目的推广。
你有两个杯子,容量分别是a和b,你周围有自来水管(水无限),问能否量出c升水,也就是要求最终两个杯子中的水加起来是c升(c<=a+b)
解:
(1)设a和b的最大公约数是x,那么能量出c,当且仅当x能整除c。因为***(a,b)=x,则必然存在p和q,使得a*p+b*q=x。可以看到p和q必然一正一负,我们假设q为负(p为负的情况分析类似)。
那么我们先考虑如何量出x升水,从等式上看,过程就是我们设法灌满a水杯p次,再倒出q次b升水,剩下的就是恰好x升水。
举个例子吧:假设a=4,b=9,则b-2*a=1,那么倒出一升水就是先用b装9升水,然后把a倒满,把a中的水扔掉,b再把a灌满,把a中的水再仍掉。可以看到最终两个水杯中的水加起来是1.
再举个例子:假设a=2, b=3,则2*a - b=1,量出1升水的过程就是:把a灌满,a倒入b,再把a灌满,a把b倒满,把b中的水扔掉,a中恰好剩下1.
可以看到若***(a,b)=x,那么a*p+b*q=x,蕴含了量出x升水的过程。现在如果x能整除c,那么必然存在u,v,使得a*u+b*v=c(其实就是上述等式两边乘以c/x)。
这个等式也蕴涵了量出c升水的过程。
举个例子:a=4, b=9, c=3,我们用full(a)表示把a灌满, empty(a)表示把a倒空,a->b表示把a倒向b,结果要门是a空或者b满(否则后续操作将无法进行,因为我们不知道两者确切的水量)。
那么b-2*a=1 => 3*b - 6*a =3,过程就是:
full(b), b->a, empty(a), b->a, emtpy(a), b->a,(此时a=1,b=0),full(b), b->a,emtpy(a),b->a,empty(a),b->a,(此时a=2,b=0),full(b), b->a, emtpy(a),b->a,empty(a) ,现在b中正好剩下3.
(2)现在证明若c不是***(a,b)的倍数,那么c一定无法量出来。
我们知道若***(a,b)=x不能整除c,那么一定不存在p和q,使得a*p+b*q=c成立。那么我们只要证明任何操作a和b的过程,最终都可以用a*u+b*v表示。
我们看对a和b的操作无非就是 full(a),empty(a),a->b,full(b),empty(b),b->a。
两个都是满的状态和两个都是空的状态是一样的;一个满一个空,能进行的有意义的操作就是从一个倒向另一个,假设a->b,结束是a空或者b满,假设b满a非空,那么下一步把a倒掉,没啥意义(因为回到了一个非常简单的状态),所以需要把b倒掉,那么再下一步呢?把a贵满吗?也没啥意义(因为也回到了一个非常简单的状态)。
通过归纳,可一发现有意义的操作都是把空贵满,或把满的倒空。而把半空的灌满或者倒空都没意义(注意任何一个时刻a和b不可能都半空)。也就是说上说6种操作的一个序列,可以加上条件。也就是full(a)的时候要求是a是空的,empty(a)的时候要求a是满的。
这样任何一个操作过程最终就可以表示为a*u+b*v。 

我们把这个题目变通一下:假设有n个瓶子,每个容量不一,问能否量出c升水来?
同样结论是:n个瓶子的最大公约数为x,则能量出c当且仅当x整除c。

原文地址:https://www.cnblogs.com/chkkch/p/2759687.html