編碼也快樂:兩隻水壺Scheme程式

空軍發表於2013-04-15

編碼任務
假設有一個池塘,裡面有無窮多的水。現有2個空水壺,容積分別為5升和6升。如何只用這2個水壺從池塘裡取得3升的水(最後,這三升水,在其中一個壺裡)

分析

顯然,水壺的容積必須為正數,目標水量必須非負,且不能超過容量大的那個水壺的容積。如果目標水量及兩個水壺的容積分別用 t、a、b 來表示,則必須有 a > 0, b > 0, 0 ≤ t ≤ max(a, b)。另外,t、a、b 三個量必須可公度,它們可以是有理數。如果都乘以分母的最小公倍數,即可化為整數。因此,我們僅需考慮 t、a、b 都是整數的情形。

令 d 是 a 和 b 的最大公約數。由於 a 和 b 都是 d 的倍數,如果 t 不是 d 的倍數,把 d 升水考慮為 1 份水,可知原題無解。另一方面,數論中有一個定理1,方程 ax + by = t 有整數解 x, y,當且僅當 t 是 d 的倍數。因此,如果 t 是 d 的倍數,按照歐幾里得演算法的步驟,原題可解。

  1. 參見“最大公約數與歐幾里得演算法”中的定理25

Scheme

Lisp 是第一個函式式程式設計語言,已經使用了半個世紀。在現存的活語言裡,只有 Fortran 比它的壽命更長些。這兩種語言都支援著一些重要領域中的程式設計需要,Fortran 用於科學與工程計算,Lisp 用於人工智慧。這兩個領域現在仍然很重要,它們的程式設計師都如此傾心於這兩種語言,因此,Lisp 和 Fortran 都還可能繼續生存至少半個世紀。

Scheme 是 Lisp 兩種主要的方言之一(另一種為 Common Lisp)。它的精簡性與優雅的語法廣受電腦科學教育者以及語言設計學者的歡迎,並經常被用於基礎電腦科學教育上。麻省理工學院與其他院校曾利用 Scheme 教授入門課程,著名的入門教材《計算機程式的構造和解釋》(SICP,或稱“魔法書”)就是利用 Scheme 來解釋程式設計。

我這裡用的是 MIT/GNU Scheme,可到官網 http://www.gnu.org/software/mit-scheme 下載 GNU/Linux、OS X 和 Windows 等平臺的安裝包。

兩隻水壺程式

言歸正傳,解釋一下我的 Scheme 程式:

主函式 pot 的三個引數 t a b 分別是目標水量及兩個壺的容積。

函式 solve 用於解題,引數 p q 是兩個壺的當前水量。
(巢狀函式 x,計算從 A 壺最多能往 B 壺倒多少水)
函式 solve 首先列印當前水量;
如果當前水量等於目標水量,成功;
否則,如果 A 壺空,則裝滿它;
否則,如果 B 壺滿,則清空它;
否則,儘可能地從 A 壺往 B 壺倒水;
遞迴地呼叫以上步驟即可完成解題。

主函式 pot 首先判斷輸入的引數 t a b 是否超出允許範圍;
接著根據目標水量是不是兩個壺的容積的最大公約數的倍數判斷是否有解;
現在可以置兩個壺的初始水量為零,呼叫函式 solve 0 0 開始解題。

(define (pot t a b)
  (define (solve p q)
    (define x (min p (- b q)))
    (display " -> ") (display p) (display " ") (display q) (newline)
    (cond ((or (= p t) (= q t)) (display "------- OK! ------"))
      ((= p 0) (display "Fill A full") (solve a q))
      ((= q b) (display "Empty pot B") (solve p 0))
      (else (display "Pour A to B") (solve (- p x) (+ q x)))))
  (cond ((or(< a 1)(< b 1)(< t 0)(> t (max a b))) (display "Arg out of range"))
    ((not (= (remainder t (gcd a b)) 0)) (display "No solve!"))
    (else (display "Start with ") (solve 0 0)))) 

以目標水量 3,兩個壺的容積分別為 5 和 6 為引數呼叫 pot 的結果如下:

(pot 3 5 6)

Start with  -> 0 0
Fill A full -> 5 0
Pour A to B -> 0 5
Fill A full -> 5 5
Pour A to B -> 4 6
Empty pot B -> 4 0
Pour A to B -> 0 4
Fill A full -> 5 4
Pour A to B -> 3 6
------- OK! ------

美國人的火箭發射系統

上世紀七十年代,前蘇聯情報機構克格勃對美國太空技術軟體發生了濃厚的興趣,派遣了各種各樣的間諜蒐集任何可能的相關資訊。

一天下午,一個間諜氣喘吁吁的回到總部,手裡拿著一張紙,興奮的對著他的上司叫喊,“同志!同志!美國人的火箭發射系統是用 Lisp 語言編寫的!”

長官很疑惑:“你怎麼知道的?”

“我闖進了他們的研究室,從他們的電傳機上偷了一張紙!這上面不是整個程式,只是最後一頁,記錄了程式的結束部分!你自己看!!!”

長官看著這張紙笑了:

))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))

傾情推薦

相關文章