代序
多年前的一個晚上,本書作者找到我,說會在《程序員》雜志連載一系列文章,主題是生活中的算法。連載結(jié)束后,會集結(jié)成冊匯成一本書,他想請我為這本八字還沒一撇的書繪制插圖。
一開始我是拒絕的。我既不是專業(yè)插畫師,對所謂生活中的算法也沒什么概念,這本書能不能順利出版也還是未知數(shù),但在他的一再堅持下,最終還是答應了這個縹緲的請求。當時我倆誰也沒想到,他所說的這本書,從連載到最后成型出版,整整醞釀了八年。這八年間,我已經(jīng)和他結(jié)了婚,我們的兩個孩子都比這本書先“問世”了。
連載的那段時間,他每完成一篇文章,都會先發(fā)給我看看。而我作為這個系列的第一個讀者,每次看完都會反饋給他能不能看懂、有沒有問題、好不好玩,從一個業(yè)余讀者的角度,盡可能地監(jiān)督他把問題簡單有趣地講明白。
一個算法,可以講到它的前世今生,講到它在生活中的應用,就連我們在生活中遇到的真實問題,也被他寫進書里做例子,甚至附上了日期時間?缭桨四辏行├右矌狭诵┰S年代感,令人感嘆。
臨近出版,該給書寫個序了。他坐在我邊上盯著屏幕發(fā)呆,似乎沒什么思路。瞄了一眼屏幕,這個家伙竟然在一本正經(jīng)地搜索“如何給一本書寫序”……我說要不我先從我的角度寫寫吧,拋磚引玉,看看我寫完能不能給你點靈感。于是便有了這篇代序。
——蔡雪琴,2021 年 8 月
序言
小學時,我特別喜歡解數(shù)學謎題。為了把狼、羊、白菜運到河對岸,為了找出重量較輕的那枚假幣,為了在 3 分鐘內(nèi)煎好全部大餅,為了判斷出誰是騎士誰是無賴,我常常會廢寢忘食地在紙上寫寫畫畫,最后為自己發(fā)現(xiàn)了答案而興奮不已。有個謎題讓我至今記憶猶新:把 4 個 A、4 個 B、4 個C、4 個 D 排成一個 4 × 4 的方陣,使得每一行都沒有重復的字母,每一列也沒有重復的字母。我把它解決了,而且獲得了更大的爽快感。因為,問題的答案并不是我盲目地試出來的,而是用一個自己想到的“招數(shù)”得出的。在第一排按順序?qū)懴?A、B、C、D 這 4 個字母,然后把第一個字母挪到最后面,變成下一排的字母順序,并且不斷地這樣做下去。等 4 排都寫完了,就會得到一個正確的答案。
A B C D
B C D A
C D A B
D A B C
而且我發(fā)現(xiàn),這個“招數(shù)”十分萬能,它可以直接用于字母更多的情況,F(xiàn)在回想起來,這沒準兒是我解決的第一個算法問題。
中學時,我開始搞信息學競賽,才知道這是一個經(jīng)典問題,叫作拉丁方陣(Latin square)。當年我找到的,不過是 4 階拉丁方陣的一個最基本的解。4 階拉丁方陣還有很多,有些沒法拿我當年的“招數(shù)”得出,比如下面這個:
A D B C
B C A D
C B D A
D A C B
更讓我吃驚的是,這個看似純粹的數(shù)字游戲,在生產(chǎn)生活中竟然有非常真實的應用。假設某汽車發(fā)動機制造商想要測試并比較 4 種汽油添加劑的性能。不妨把這 4 種汽油添加劑分別記作 A、B、C、D。如果所有試驗全在某一輛車上進行,可能會出現(xiàn)一些問題,比方說該車的某些特性正好能讓A 充分發(fā)揮性能,最終的試驗結(jié)果會顯示 A 的性能更好,但這個結(jié)論無法廣泛適用于各種場合。類似地,駕駛員的習慣或許也會無意地影響到試驗結(jié)果。為了消除這些因素的影響,我們可以選擇 4 輛不同的車(編號分別為 1、2、3、4)、4 名不同的駕駛員(編號也分別為 1、2、3、4)。在我當年得出的拉丁方陣中,第 2 行第 3 列是 D,我們就把 D 裝進 2 號車,交給3 號駕駛員去開。所有 16 次測試中,每種汽油添加劑都用了 4 次,這 4 次都是跟不同的車、不同的駕駛員搭配,而且每一名駕駛員都沒開過重復的車。這樣得到的試驗結(jié)果就能很好地反應更普遍的情況。
算法,不但是編寫程序的人需要掌握的一門學問,在人們的日常生活中也扮演著重要的角色。拉丁方陣就是一個非常好的例子。
大學時,看了不少科普書,自己也試著寫了一些。當時,市面上有很多經(jīng)濟學、心理學等“興趣學科”的優(yōu)秀科普書,既不像教科書那樣無趣,又不像“快餐書”那樣泛泛而談,不管是門外漢還是業(yè)內(nèi)人士,看完后都覺得收獲頗豐。我忽然萌生了一個想法:算法也是一個應用廣泛、妙趣橫生的學科,計算機行業(yè)內(nèi)外的人應該都會有興趣,但為什么沒有寫給大家看的算法書呢?那時,我就計劃著自己寫一本。
我和很多人分享了這個想法。2012 年,應盧鶇翔編輯的邀請,我開始為《程序員》雜志的算法欄目供稿。2013 年末,稿件數(shù)量已經(jīng)累積到我覺得比較滿意的程度了,我便著手將它們串聯(lián)并擴充成一本完整的算法書。2015年,這本書的初稿終于完成了。接下來,這本書進入了漫長而曲折的審校打磨階段,圖書編輯和插畫師輪番抱娃,耽誤了不少進度,我作為完美主義者、拖延癥患者和插畫師的孩子他爸,對此書跳票亦有卓越貢獻。一眨眼,已經(jīng)到 2020 年了。八年的時間里凝聚了太多人的智慧和汗水。這里,向所有對這本書的寫作和出版有幫助的人致謝。
最后,也想對正在閱讀序言的你說一句,祝愿這本書能陪伴你度過一段難忘的算法之旅。如果你喜歡剛才那個拉丁方陣的例子,那你可要做好準備了。拉丁方陣不過是算法這個游樂園里的旋轉(zhuǎn)木馬,后面的內(nèi)容將會像過山車一樣驚險刺激!
——顧森,2021年8月