倒水問題

michael9527發表於2020-04-06
倒水問題的經典形式是這樣的:

“假設有一個池塘,裡面有無窮多的水。現有2個空水壺,容積分別為
5升和6升。問題是如何只用這2個水壺從池塘裡取得3升的水。”

當然題外是有一些合理的限制的,比如從池塘裡灌水的時候,不管壺
裡是不是已經有水了,壺一定要灌滿,不能和另一個壺裡的水位比照
一下“毛估估”(我們可以假設壺是不透明的,而且形狀也不同);
同樣的,如果要把水從壺裡倒進池塘裡,一定要都倒光;如果要把水
從一個壺裡倒進另一個壺裡,也要都倒光,除非在倒的過程中另一個
壺已經滿了;倒水的時候水沒有損失(蒸發溢位什麼的)等等等等。

事實上,要解決上面這題,你只要用兩個壺中的其中一個從池塘裡灌
水,不斷地倒到另一個壺裡,當第二個壺滿了的時候,把其中的水倒
回池塘裡,反覆幾次,就得到答案了。以5升壺(A)灌6升壺(B)為例:
A   B
0   0
5   0   A->B
0   5
5   5   A->B
4   6
4   0   A->B
0   4
5   4   A->B
3   6

現在我們問,如果是多於2只壺的情況怎麼辦(這樣一來就不能用上面
的迴圈倒水法了)?如何在倒水之前就知道靠這些壺是一定能(或一
定不能)倒出若干升水來的?試舉數例:
1)兩個壺:65升和78升,倒38升和39升。
2)三個壺:6升,10升和45升,倒31升。

我們可以看到,在1)中,65=5*13,78=6*13,而39=3*13。所以如果把
13升水看作一個單位的話(原題中的“升”是沒有什麼重要意義的,
你可以把它換成任何容積單位,毫升,加侖——或者“13升”),這
題和最初的題目是一樣的。而38升呢?顯然是不可能的,它不是13的
倍數,而65升和78升的壺怎麼也只能倒出13升的倍數來。也可以這樣
理解:這相當於在原題中要求用5升和6升的壺倒出38/39升來。

那麼2)呢?你會發現,只用任何其中兩個壺是倒不出31升水的,理由
就是上面所說的,(6,10)=2,(6,45)=3,(10,45)=5,(這裡(a,b)是
a和b的最大公約數),而2,3,5均不整除31。可是用三個壺就可以倒
出31升:用10升壺四次,6升壺一次灌45升壺,得到1升水,然後灌滿
10升壺三次得30升水,加起來為31升。

一般地我們有“灌水定理”:

“如果有n個壺容積分別為A1,A2,……,An(Ai均為大於0的整數)
設w為另一大於0的整數。則用此n個壺可倒出w升水的充要條件為:
1)w小於等於A1+A2+……+An;
2)w可被(A1,A2,……,An)(這n個數的最大公約數)整除。”

這兩個條件都顯然是必要條件,如果1)不被滿足的話,你連放這麼多
水的地方都沒有。2)的道理和上面兩個壺的情況完全一樣,因為在任
何步驟中,任何壺中永遠只有(A1,A2,……,An)的倍數的水。

現在我們來看一下充分性。在中學裡我們學過,如果兩個整數a和b互
素的話,那麼存在兩個整數u和v,使得ua+vb=1。證明的方法很簡單:
在對a和b做歐幾里德輾轉相除時,所有中間的結果,包括最後得到的
結果顯然都有ua+vb的形式(比如第一步,假設a小於b,記a除b的結果
為s,餘數為t,即b=sa+t,則t=(-s)a+b,即u=-s,v=1)。而兩個數
互素意味著歐幾里德輾轉相除法的最後一步的結果是1,所以1也可以
記作ua+vb的形式。稍微推廣一點,如果(a,b)=c,那麼存在u和v使得
ua+vb=c(兩邊都除以c就回到原來的命題)。

再推廣一點,如果A1,A2,……,An是n個整數,(A1,A2,……,An)=s,
那麼存在整數U1,U2,……,Un,使得
   U1A1 + U2A2 + …… + UnAn = s.        (*)
在代數學上稱此結果為“整數環是主理想環”。這也不難證,只要看

(A1,A2,A3,A4,……,An)=((((A1,A2),A3),A4),……,An).
也就是說,可以反覆應用上一段中的公式:比如三個數a,b,c,它
們的最大公約數是d。假設(a,b)=e,那麼(e,c)=((a,b),c)=d。現在
有u1,u2使得u1a+u2b=e,又有v1,v2使得v1e+v2c=d,那麼
   (v1u1)a+(v1u2)b+(v2)c=d.

好,讓我們回頭看“灌水定理”。w是(A1,A2,……,An)的倍數,根據
上節的公式(*),兩邊乘以這個倍數,我們就有整數V1,V2,……,Vn
使得
   V1A1 + V2A2 + …… + VnAn = w.
注意到Vi是有正有負的。

這就說明,只要分別把A1,A2,……,An壺,灌上V1,V2,……,Vn
次(如果Vi是負的話,“灌上Vi次”要理解成“倒空-Vi次”),就可
以得到w升水了。具體操作上,先求出各Vi,然後先往Vi是正數的壺裡
灌水,灌1次就把Vi減1。再把這些水到進Vi是負數的壺裡,等某個壺
灌滿了,就把它倒空,然後給這個負的Vi加1,壺之間倒來倒去不變更
各Vi的值。要注意的是要從池塘裡灌水,一定要用空壺灌,要倒進池
塘裡的水,一定要是整壺的。這樣一直到所有Vi都是0為止。

會不會發生卡住了,既不能灌水又不能倒掉的情況?不會的。如果有
Vi仍舊是負數,而Ai壺卻沒滿:那麼如果有其它Vi是正的壺裡有水的
話,就都倒給它;如果有其它Vi是正的壺裡沒水,那麼就拿那個壺打
水來灌(別忘了給打水的壺的Vi減1);如果根本沒有任何Vi是正的壺
了——這是不可能的,這意味著w是負的。有Vi仍舊是正數,而Ai壺卻
沒滿的情況和這類似,你會發現你要用到定理中的條件1)。

這樣“灌水定理”徹底得證。當然,實際解題當中如果壺的數目和容
積都比較大的話,手工來找(*)中的各Ui比較困難,不過可以寫個程式,
連倒水的步驟都算出來。最後要指出的一點是,(*)中的Ui不是唯一的,
所以倒水的方式也不是唯一的。

 

相關文章