灌水問題

倒水問題的經典形式是這樣的:

  “假設有一個池塘,裏面有無窮多的水。現有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不是唯一的,所以倒水的方式也不是唯一的。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章