• <ins id="pjuwb"></ins>
    <blockquote id="pjuwb"><pre id="pjuwb"></pre></blockquote>
    <noscript id="pjuwb"></noscript>
          <sup id="pjuwb"><pre id="pjuwb"></pre></sup>
            <dd id="pjuwb"></dd>
            <abbr id="pjuwb"></abbr>

            糯米

            TI DaVinci, gstreamer, ffmpeg
            隨筆 - 167, 文章 - 0, 評論 - 47, 引用 - 0
            數據加載中……

            讀《程序員的十層樓》

            這篇文章看了三四次啦,開了博客就轉過來了。
            作者比較牛逼,說得都很在理,作者應該位于學者以上的層次了,不然眼光也放不到這么遠。
            包括第11層,都說得很對。上帝確實存在,自古都有敬神信神的故事,就不多說了。。

            其實程序員的目的未必是要向更高層次發展,但重要的是找到自己的層次并且做到極致。就好比李開復說的“做最好的自己”。
            很多人,包括哥,都在迷茫著。究竟怎么做,才算做到極致。。。。
            這是最大的問題。

            posted @ 2010-02-20 15:31 糯米 閱讀(297) | 評論 (0)編輯 收藏

            [轉]程序員的十層樓

            自西方文藝復興以來,中國在自然科學方面落后西方很多,軟件領域也不例外。當然現在中國的許多程序員們對此可能有許多不同的意見,有些人認為中國的程序員水平遠落后于西方,有些則認為中國的程序員個人能力并不比西方的程序員差,只是整個軟件產業落后而已。那么,到底中國的程序員水平比西方程序員水平差,還是中國有許多優秀的程序員達到或超過了西方程序員同等水平呢?要解決這個問題,必須先知道程序員 有多少種技術層級,每個層級需要什么樣的技術水平,然后再比較中國和西方在各個技術層級的人數,就可以知道到底有沒有差距,差距有多大。
            當然,對于如何劃分程序員的技術層級,不同公司或不同人會有不同的劃分標準,下面的劃分僅代表個人的觀點,如有不當之處,還請砸板磚予以糾正。

            第1層 
            菜鳥第1層樓屬于地板層,邁進這層樓的門檻是很低的。基本上懂計算機的基本操作,了解計算機專業的一些基礎知識,掌握一門基本的編程語言如C/C++,或者Java,或者JavaScript,...,均可入門邁進這層。
            在這層上,中國有著絕對的優勢,除了從計算機專業畢業的眾多人數外,還有大量的通信、自動化、數學等相關專業的人士進入這一行,此外還有眾多的其他專業轉行的人士,人數絕對比西方多出甚多。并且還有一個優勢就是我們這層人員的平均智商比西方肯定高。
            沒有多少人愿意一輩子做菜鳥,因為做"菜鳥"的滋味實在是不咋的,整天被老大們吆喝著去裝裝機器,搭建一下測試環境,或者對照著別人寫好的測試用例 做一些黑盒測試,好一點的可以被安排去寫一點測試代碼。當然如果運氣"好"的話,碰到了國內的一些作坊式的公司,也有機會去寫一些正式的代碼。
            所以,菜鳥們總是在努力學習,希望爬更高的一層樓去。

            第2層
            大蝦從第1層爬到第2層相對容易一些,以C/C++程序員為例,只要熟練掌握C/C++編程語言,掌握C標準庫和常用的各種數據結構算法,掌握STL的 基本實現和使用方法,掌握多線程編程基礎知識,掌握一種開發環境,再對各種操作系統的API都去使用一下,搞網絡編程的當然對socket編程要好好掌握 一下,然后再學習一些面向對象的設計知識和設計模式等,學習一些測試、軟件工程和質量控制的基本知識,大部分人經過2~3年的努力,都可以爬到第2層,晉 升為"大蝦"。
            中國的"大蝦"數量和"菜鳥"數量估計不會少多少,所以這層上仍然遠領先于西方。
            大蝦們通常還是有些自知之明,知道自己只能實現一些簡單的功能,做不了大的東西,有時候還會遇到一些疑難問題給卡住,所以他們對那些大牛級的人物通 常是非常崇拜的,國外的如Robert C. Martin、Linus Torvalds,國內的如求伯君、王志東等通常是他們崇拜的對象。其中的有些人希望有一天也能達到這些大牛級人物的水平,所以他們繼續往樓上爬去。


            第3層
            牛人由于"大蝦"們經常被一些疑難問題給卡住,所以有了"大蝦"們只好繼續學習,他們需要將原來所學的知識進一步熟練掌握,比如以熟練掌握C++編程語 言為例,除了學一些基礎性的C++書籍如《C++ Primer》,《Effective C++》,《Think in C++》,《Exception C++》等之外,更重要的是需要了解C++編譯器的原理和實現機制,了解操作系統中的內部機制如內存管理、進程和線程的管理機制,了解處理器的基礎知識和 代碼優化的方法,此外還需要更深入地學習更多的數據結構與算法,掌握更深入的測試和調試知識以及質量管理和控制方法,對各種設計方法有更好的理解等。
            學習上面說的這些知識不是一揮而就的,不看個三五十本書并掌握它是做不到的。以數據結構算法來說,至少要看個5~10本這方面的著作;以軟件設計來 說,光懂結構化設計、面向對象設計和一些設計模式是不夠的,還要了解軟件架構設計、交互設計、面向方面的設計、面向使用的設計、面向數據結構算法的設計、 情感化設計等,否則是很難進到這個樓層的。
            當然除了上面說的知識外,大蝦們還需要去學習各種經驗和技巧。當然這點難不倒他們,現在出版的書籍眾多,網絡上的技術文章更是不勝數,然后再去各種 專業論壇里泡一泡,把這些書籍和文章中的各種經驗、技能、技巧掌握下來,再去學習一些知名的開源項目如Apache或Linux操作系統的源代碼實現等。 此時對付一般的疑難問題通常都不在話下,菜鳥和大蝦們會覺得你很"牛",你也就爬到了第3層,晉升為"牛人"了。
            看了上面所講的要求,可能有些大蝦要暈過去了,成為牛人要學這么多東西啊!要求是不是太高了?其實要求一點也不高,這么點東西都掌握不了的話,怎么能讓別人覺得你"牛"呢?

            需要提一下的是,進入多核時代后,從第2層爬到第3層增加了一道多核編程的門檻。當然要邁過這道門檻并不難,已經有很多前輩高人邁進了這道門檻,只要循著他們的足跡前進就可以了。想邁進這道門檻者不妨去學習一下TBB開源項目的源代碼(鏈接:http://www.threadingbuildingblocks.org/),然后上Intel的博客(http://softwareblogs-zho.intel.com/)和多核論壇(http://forum.csdn.net/Intel/IntelMulti-core/)去看看相關文章,再買上幾本相關的書籍學習一下。

            在國內, 一旦成為"牛人",通常可以到許多知名的公司里去,運氣好者可以掛上一個架構師的頭銜,甚至掛上一個"首席架構師"或者"首席xx學家"的頭銜也不足為 奇。有不少爬到這層的人就以為到了樓頂了,可以眼睛往天上看了,開始目空一切起來,以為自己什么都可以做了,什么都懂了,經常在網絡上亂砸板磚是這個群體 的最好寫照。由此也看出,國內的牛人數量仍然眾多,遠多于西方的牛人數量,在這層上仍然是領先的。
            也有不少謙虛的"牛人",知道自己現在還不到半桶水階段。他們深知爬樓的游戲就像猴子上樹一樣,往下看是笑臉,往上看是屁股。為了多看笑臉,少看屁股,他們并沒有在此停步不前,而是繼續尋找到更上一層的樓梯,以便繼續往上爬。
             

            第4層
             大牛從第3層爬到第4層可不像上面說過的那幾層一樣容易,要成為大牛的話,你必須要能做牛人們做不了的事情,解決牛人們解決不了問題。比如牛人們通常都 不懂寫操作系統,不會寫編譯器,不懂得TCP/IP協議的底層實現,如果你有能力將其中的任何一個實現得象模象樣的話,那么你就從牛人升級為"大牛"了。
            當然,由于各個專業領域的差別,這里舉操作系統、編譯器、TCP/IP協議只是作為例子,并不代表成為"大牛"一定需要掌握這些知識,以時下熱門的 多核編程來說,如果你能比牛人們更深入地掌握其中的各種思想原理,能更加自如的運用,并有能力去實現一個象開源項目TBB庫一樣的東西,也可以成為"大 牛",又或者你能寫出一個類似Apache一樣的服務器,或者寫出一個數據庫,都可以成為"大牛"。
            要成為"大牛"并不是一件簡單的事情,需要付出比牛人們多得多的努力,一般來說,至少要看過200~400本左右的專業書籍并好好掌握它,除此之外,還得經常關注網絡和期刊雜志上的各種最新信息。
            當"牛人"晉升為"大牛",讓"牛人們"發現有比他們更牛的人時,對"牛人"們的心靈的震撼是可想而知的。由于牛人們的數量龐大,并且牛人對大蝦和 菜鳥階層有言傳身教的影響,所以大牛們通常能獲得非常高的社會知名度,幾乎可以用"引無數菜鳥、大蝦、牛人競折腰"來形容,看看前面提過的Linus Torvalds等大牛,應該知道此言不虛。
            雖然成為"大牛"的條件看起來似乎很高似的,但是這層樓并不是很難爬的一層,只要通過一定的努力,素質不是很差,還是有許多"牛人"可以爬到這一層的。由此可知,"大牛"這個樓層的人數其實并不像想像的那么少,例如比爾·蓋茨之類的人好像也是屬于這一層的。
            由于"大牛"這層的人數不少,所以也很難統計除到底是中國的"大牛"數量多還是西方的大牛數量多?我估計應該是個旗鼓相當的數量,或者中國的"大牛"們會更多一些。
            看到這里,可能會有很多人會以為我在這里說瞎話,Linus Torvalds寫出了著名的Linux操作系統,我國并沒有人寫出過類似的東西啊,我國的"大牛"怎么能和西方的比呢? 不知大家注意到沒有,Linus Torvalds只是寫出了一個"象模象樣"的操作系統雛形,Linux后來真正發展成聞名全球的開源操作系統期間,完全是因為許多支持開源的商業公司如 IBM等,派出了許多比Linus Torvalds更高樓層的幕后英雄在里面把它開發出來的。
            可能有些菜鳥認為Linus Torvalds是程序員中的上帝,不妨說個小故事:
            Linus,Richard Stallman和Don Knuth(高德納)一同參加一個會議。
            Linus 說:"上帝說我創造了世界上最優秀的操作系統。"
            Richard Stallman自然不甘示弱地說:"上帝說我創造了世界上最好用的編譯器。"
            Don Knuth一臉疑惑的說:"等等,等等,我什么時候說過這些話?"
            由此可以看出,Linus Torvalds的技術水平并不像想像中那么高,只是"牛人"和"大蝦"覺得"大牛"比他們更牛吧了。在我國,有一些當時還處于"大蝦"層的人物,也能寫 出介紹如何寫操作系統的書,并且書寫得非常出色,而且寫出了一個有那么一點點象模象樣的操作系統來。我想中國的"大牛"們是不會比西方差的,之所以沒有人 寫出類似的商業產品來,完全是社會環境的原因,并不是技術能力達不到的原因。
            "大牛"們之所以成為大牛,主要的原因是因為把"牛人"給蓋了下去,并不是他們自己覺得如何牛。也許有很多菜鳥、大蝦甚至牛人覺得"大牛"這層已經 到頂了,但大多數"大牛"估計應該是有自知之明的,他們知道自己現在還沒有爬到半山腰,也就勉強能算個半桶水的水平,其中有些爬到這層沒有累趴下,仍然能 量充沛,并且又有志者,還是會繼續往更上一層樓爬的。
            看到這里,也許有些菜鳥、大蝦、牛人想不明白了,還有比"大牛"們更高的樓層,那會是什么樣的樓層?下面就來看看第5層樓的奧妙。


            第5層
             專家當大牛們真正動手做一個操作系統或者類似的其他軟件時,他們就會發現自己的基本功仍然有很多的不足。以內存管理為例,如果直接抄襲Linux或者其 他開源操作系統的內存管理算法,會被人看不起的,如果自動動手實現一個內存管理算法,他會發現現在有關內存管理方法的算法數量眾多,自己并沒有全部學過和 實踐過,不知道到底該用那種內存管理算法。
            看到這里,可能有些人已經明白第5層樓的奧妙了,那就是需要做基礎研究,當然在計算機里,最重要的就是"計算"二字,程序員要做基礎研究,主要的內容就是研究非數值"計算"。
            非數值計算可是一個非常龐大的領域,不僅時下熱門的"多核計算"與"云計算"屬于非數值計算范疇,就是軟件需求、設計、測試、調試、評估、質量控 制、軟件工程等本質上也屬于非數值計算的范疇,甚至芯片硬件設計也同樣牽涉到非數值計算。如果你還沒有真正領悟"計算"二字的含義,那么你就沒有機會進到 這層樓來。
            可能有人仍然沒有明白為什么比爾·蓋茨被劃在了大牛層,沒有進到這層來。雖然比爾·蓋茨大學未畢業,學歷不夠,但是家有藏書2萬余冊,進入軟件這個 行業比絕大部分人都早,撇開他的商業才能不談,即使只看他的技術水平,也可以算得上是學富五車,頂上幾個普通的計算機軟件博士之和是沒有問題的,比起 Linus Torvalds之類的"大牛"們應該技高一籌才對,怎么還進不了這層樓呢?
            非常遺憾的是,從Windows操作系統的實現來看,其對計算的理解是很膚淺的,如果把Google對計算方面的理解比做大學生,比爾·蓋茨只能算做一個初中生,所以比爾·蓋茨永遠只能做個大牛人,成不了"專家"。
            看到這里,也許國內的大牛們要高興起來了,原來比爾·蓋茨也只和我等在同一個層次,只要再升一層就可以超越比爾·蓋茨了。不過爬到這層可沒有從"牛 人"升為"大牛"那么簡單,人家比爾·蓋茨都家有2萬多冊書,讓你看個500~1000本以上的專業書籍并掌握好它應該要求不高吧。當然,這并不是主要的 條件,更重要的是,需要到專業的學術站點去學習了,到ACM,IEEE,Elsevier,SpringerLink,SIAM等地方去下載論文應該成為 你的定期功課,使用Google搜索引擎中的學術搜索更是應該成為你的日常必修課。此外,你還得經常關注是否有與你研究相關的開源項目冒出來,例如當聽到 有TBB這樣針對多核的開源項目時,你應該第一時間到Google里輸入"TBB"搜索一下,將其源代碼下載下來好好研究一番,這樣也許你的一只腳已經快 邁進了這層樓的門檻。
            當你象我上面說的那樣去做了以后,隨著時間的推移,總會有某天,你發現,在很多小的領域里,你已經學不到什么新東西了,所有最新出來的研究成果你幾 乎都知道。此時你會發現你比在做"牛人"和"大牛"時的水平不知高出了多少,但是你一點也"牛"不起來,因為你學的知識和思想都是別人提出來的,你自己并 沒有多少自己的知識和思想分享給別人,所以你還得繼續往樓上爬才行。
            我不知道國內的"專家"到底有多少,不過有一點可以肯定的是,如果把那些專門蒙大家的"磚家"也算上的話,我們的磚家比西方的要多得多。
             

            第6層 學者
            當"專家"們想繼續往上一層樓爬時,他們幾乎一眼就可以看到樓梯的入口,不過令他們吃驚的是,樓梯入口處豎了一道高高的門檻,上面寫著"創新"二字。不幸的是,大多數人在爬到第5層樓時已經體能消耗過度,無力翻過這道門檻。
            有少數體能充足者,可以輕易翻越這道門檻,但是并不意味著體力消耗過度者就無法翻越,因為你只是暫時還沒有掌握恢復體能的方法而已,當掌握了恢復體能的方法,將體能恢復后,你就可以輕易地翻越這道門檻了。
            怎么才能將體能恢復呢?我們的老祖宗"孔子"早就教導過我們"溫故而知新",在英文里,研究的單詞是"research",其前綴"re" 和"search"分別是什么意思不用我解釋吧。或許有些人覺得"溫故而知新"和"research"有些抽象,不好理解,我再給打個簡單的比方,比如你 在爬一座高山,爬了半天,中途體力不支,怎么恢復體力呢?自然是休息一下,重新進食一些食物,體力很快就可以得到恢復。
            由此可知,對體能消耗過度者,休息+重新進食通常是恢復體能的最佳選擇。可惜的是,國內的老板們并不懂得這點,他們的公司里不僅連正常國家規定的休 息時間都不給足,有些公司甚至有員工"過勞死"出現。所以國內能翻越"創新"這道門檻的人是"少之又少",和西方比起來估計是數量級的差別。
            再說說重新進食的問題,這個重新進食是有講究的,需要進食一些基礎性易消化的簡單食物,不能進食山珍海味級的復雜食物,否則很難快速吸收。以查找為 例,并不是去天天盯著那些復雜的查找結構和算法進行研究,你需要做的是將二分查找、哈希查找、普通二叉樹查找等基礎性的知識好好地復習幾遍。
            以哈希查找為例,首先你需要去將各種沖突解決方法如鏈式結構、二次哈希等編寫一遍,再試試不同種類的哈希函數,然后還需要試試在硬盤中如何實現哈希 查找,并考慮數據從硬盤讀到內存后,如何組織硬盤中的數據才能快速地在內存中構建出哈希表來,...,這樣你可能需要將一個哈希表寫上十幾個不同的版本, 并比較各個版本的性能、功能方面的區別和適用范圍。
            總之,對任何一種簡單的東西,你需要考慮各種各樣的需求,以需求來驅動研究。最后你將各種最基礎性的查找結構和算法都了然于胸后,或許某天你再看其他更復雜的查找算法,或者你在散步時,腦袋里靈光一現,突然間就發現了更好的方法,也就從專家晉升為"學者"了。
            學者所做的事情,通常都是在前人的基礎上,進行一些小的優化和改進,例如別人發明了鏈式基數排序的方法,你第1個發現使用一定的方法,可以用數組替代鏈表進行基數排序,性能還能得到進一步提高。
            由于學者需要的只是一些小的優化改進,因此中國還是有一定數量的學者。不過和國外的數量比起來,估計少了一個數量級而已。
            也許有人會覺得現在中國許多公司申請專利的數量達到甚至超過西方發達國家了,我們的學者數量應該不會比他們少多少。因此,有必要把專利和這里說的創新的區別解釋一下。
            所謂專利者,只要是以前沒有的,新的東西,都可以申請專利;甚至是以前有的東西,你把他用到了一個新的領域的產品里去,也可以申請專利。比如你在房 子里造一個水泥柱子,只要以前沒有人就這件事申請專利,那么你就可以申請專利,并且下次你把水泥柱子挪一個位置,又可以申請一個新的專利;或者你在一個柜 子上打上幾個孔,下次又把孔的位置改一改,...,均可申請專利。
            這層樓里所說的創新,是指學術層面的創新,是基礎研究方面的創新,和專利的概念是完全不同的,難度也是完全不同的。你即使申請了一萬個象那種打孔一類的專利,加起來也夠不到這層樓里的一個創新。
            當你爬到第6層樓時,你也許會有一種突破極限的快感,因為你終于把那道高高的寫著"創新"二字的門檻給翻過去了,實現了"0"的突破。這時,你也許 有一種"獨上高樓,欲望盡天涯路"的感覺,但是很快你會發現看到的都是比較近的路,遠處的路根本看不清楚。如果你還有足夠的體力的話,你會想爬到更高一層 的樓層去。


            第7層 大師
            從第6層樓爬到第7層樓,并沒有多少捷徑可走,主要看你有沒有足夠的能量。你如果能象Hoare一樣設計出一個快速排序的算法;或者象Eugene W. Myers一樣設計出了一個用編輯圖的最短路徑模型來解決diff問題的算法;或者象M.J.D. Powell一樣提出了一個能夠處理非線性規劃問題的SQP方法;或者你發現基于比較的排序算法,它的復雜度下界為O(NLogN);或者你發現用棧可以 將遞歸的算法變成非遞歸的;或者你設計出一個紅黑樹或者AVL樹之類的查找結構;或者你設計出一個象C++或Java一樣的語言;或者你發明了 UML;...,你就爬到了第7層,晉升為"大師"了。
            上面舉的這些例子中,其中有些人站的樓層比這層高,這里只是為了形象說明而舉例他們的某個成就。從上面列出的一些大師的貢獻可以看出,成為大師必須 要有較大的貢獻。首先解決問題必須是比較重要的,其次你要比前輩們在某方面有一個較大的提高,或者你解決的是一個全新的以前沒有解決過的問題;最重要的 是,主要的思路和方法必須是你自己提供的,不再是在別人的思路基礎上進行的優化和改進。
            看了上面這些要求,如果能量不夠的話,你也許會覺得有些困難,所以不是每個人都能成為"大師"的。中國軟件業里能稱得上是"大師"的人,用屈指可數來形容,估計是綽綽有余。值得一提得是,國外的"大師"就象我們的"大牛"一樣滿天飛的多。
            我把我猜測本國有可能進到這層樓的大師列一下,以起個拋磚引玉的作用。漢王的"手寫識別"技術由于是完全保密的,不知道它里面用了什么思想,原創思 想占的比重有多少,因此不知道該把它劃到這層樓還是更高一層樓去。原山東大學王小云教授破解DES和MD5算法時,用到的方法不知道是不是完全原創的,如 果是的話也可進到這層樓來。
            陳景潤雖然沒有徹底解決哥德巴赫猜想,但他在解決問題時所用的方法是創新的,因此也可以進到這層樓來。當然,如果能徹底解決哥德巴赫猜想,那么可以算到更高的樓層去。
            求伯君和王志東等大牛們,他們在做WPS和表格處理之類的軟件時,不知是否有較大的原創算法在里面,如果有的話就算我錯把他們劃到了大牛層。由于所 學有限,不知道國內還有那些人能夠得上"大師"的級別,或許有少量做研究的教授、院士們,可以達到這個級別,有知道的不妨回個帖子晾一晾。
            鑒于"大師"這個稱號的光環效應,相信有不少人夢想著成為"大師"。或許你看了前面舉的一些大師的例子,你會覺得要成為大師非常困難。不妨說一下,現在有一條通往"大師"之路的捷徑打開了,那就是多核計算領域,有大量的處女地等待大家去挖掘。
            以前在單核時代開發的各種算法,現在都需要改寫成并行的。數據結構與算法、圖像處理、數值計算、操作系統、編譯器、測試調試等各個領域,都存在大量的機會,可以讓你進到這層樓來,甚至有可能讓你進到更高一層樓去。
             

            第8層 科學家

            科學家向來都是一個神圣的稱號,因此我把他放在了“大師”之上。要成為科學家,你的貢獻必須超越大師,不妨隨便舉一些例子。

            如果你象Dijkstra一樣設計了ALGOL語言,提出了程序設計的三種基本結構:順序、選擇、循環,那么你可以爬到第8層樓來。順便說一下,即使拋開這個成果,Dijkstra憑他的PV操作和信號量概念的提出,同樣可以進到這層樓。

            如果你象Don Knuth一樣,是數據結構與算法這門學科的重要奠基者,你也可以進到這層樓來。當然,數據結構和算法這門學科不是某個人開創的,是許多大師和科學家集體開創的。

            如果你象巴科斯一樣發明了Fortran語言,并提出了巴科斯范式,對高級程序語言的發展起了重要作用,你也可以進到這層樓來。

            或者你象Ken Thompson、Dennis Ritchie一樣發明了Unix操作系統和功能強大、高效、靈活、表達力強的C語言,對操作系統理論和高級編程語言均作出重大貢獻,那么你也可以進到這層樓來。

            或者你有Frederick P. Brooks一樣機會,可以去領導開發IBM的大型計算機System/360和OS/360操作系統,并在失敗后反思總結,寫出《人月神話》,對軟件工程作出里程碑式的貢獻,你也可以進到這層來。

            或者你提出了面向對象設計的基本思想,或者你設計了互聯網的TCP/IP協議,或者你象Steven A.Cook一樣奠定NP完全性的理論基礎,或者你象Frances Allen一樣專注于并行計算來實現編譯技術,在編譯優化理論和技術取得基礎性的成就,…,均可進入這層。

            當然,如果你發明了C++語言或者Java語言,你進不到這層來,因為你用到的主要思想都是這層樓中的科學家提出的,你自己并沒有沒有多少原創思想在里面。

            看了上面列出的科學家的成就,你會發現,要成為“科學家”,通常要開創一門分支學科,或者是這個分支學科的奠基者,或者在某個分支學科里作出里程碑式的重大貢獻。如果做不到這些的話,那么你能象Andrew C. Yao(姚期智)一樣在對計算理論的多個方向如偽隨機數生成,密碼學與通信復雜度等各個方向上作出重要貢獻,成為集大成者,也可以進入這層樓。

            成為“科學家”后,如果你有幸象Dijkstra一樣,出現在一個非常重視科學的國度。當你去世時,你家鄉滿城的人都會自動地去為你送葬。不過如果不幸生錯地方的話,能不挨“板磚”估計就算萬幸了。

            從上面隨便舉的一些例子中,你可能能猜到,西方科學家的數量是非常多的,于是你會想中國應該也有少量的科學家吧?我可以很負責任地告訴你一個不幸的結果,中國本土產生的科學家的數量為0。目前在國內,軟件領域的唯一的科學家就是上面提過的姚期智,還是國外請回來的,并不是本土產生的。

            可能你不同意我說的本土科學家數量為0的結論,因為你經常看到有許多公司里都有所謂“首席XX科學家”的頭銜。我想說的是,這些所謂的“首席XX科學家”都是遠遠夠不到這層樓的級別的,有些人的水平估計也就是一個“牛人”或“大牛”的級別,好一點的最多也就一個“學者”的級別。尤其是那些被稱作“首席經X學家”的,基本上可以把稱號改為“首席坑大家”。

            雖然我國沒有人能爬到這層樓上來,但是西方國家仍然有許多人爬到了比這層更高的樓上。如果要問我們比西方落后多少?那么可以簡單地回答為:“落后了三層樓”。下面就來看看我們做夢都沒有到過的更高一層樓的秘密。



            第9層 大科學家

            進入這層樓的門檻通常需要一些運氣,比如某天有個蘋果砸到你頭上時,你碰巧發現了萬有引力,那么你可以進到這層樓來。當然,萬有引力幾百年前就被人發現了,如果你現在到處嚷嚷著說你發現了萬有引力,恐怕馬上會有人打110,然后警察會把你送到不正常人類的聚集地去。因此,這里舉萬有引力的例子,只是說你要有類似的成就才能進到這層樓來。

            牛頓發現萬有引力定律開創 了經典物理運動力學這門學科,如果你也能開創一門大的學科,那么你就從科學家晉升為“大科學家”。比如愛因斯坦創建了相對論,從一個小職員變成了大科學 家。當然大科學家可遠不止這兩人,數學界里比物理學界更是多得多,如歐幾里得創建了平面幾何,笛卡爾開創解析幾何,還有歐拉、高斯、萊布尼茨等數不清的人 物,跟計算相關的大科學家則有圖靈等人。

            從上面列出的一些大科學家 可以發現,他們的成就不僅是開創了一個大的學科,更重要的是他們的成就上升到了“公理”的層面。發現公理通常是需要一點運氣的,如果你的運氣不夠好的話, 另外還有一個笨辦法也可以進到這層樓來,那就是成為集大成者。例如馮·諾伊曼,對數學的所有分支都非常了解,許多領域都有較大的貢獻,即使撇開他對計算機 的開創貢獻,成為大科學家照樣綽綽有余。

            當然,程序員們最關心的是 自己有沒有機會變成大科學家。既然計算機這門大學科的開創性成果早就被馮·諾伊曼、圖靈等人摘走了,那么程序員們是不是沒有機會變成大科學家了呢?我們的 古人說得好:“江山代有才人出,各領風騷數百年”,現在在計算機這門學科下面誕生了許多非常重要的大的分支,所以你還是有足夠的機會進到這層樓的。

            如果你能夠徹底解決自然語言理解(機器翻譯)這門學科中的核心問題, 或者你在人工智能或者機器視覺(圖像識別)方面有突破性的發現,那么你同樣可以輕易地晉升為“大科學家”。這樣當某天你老了去世時,或許那天國人已經覺醒,你也能享受到如Dijkstra一樣的待遇,有滿城甚至全國的人去為你送葬。

            現在還剩下另外一個大家感興趣的問題沒有討論,那就是這層中已經出現了牛頓、愛因斯坦、高斯等我們平常人都認為是頂級的科學家,是不是這層已經是樓頂了呢?相信還記得本文標題的人應該知道現在僅僅是第9層,還有第10層沒有到達呢。可能不少人現在要感到困惑了,難道還有人站在比牛頓、愛因斯坦、高斯等人更高的樓層上?

            這個世界上確實存在可以用一只手的手指數得清的那么幾個人,他們爬到了第10層樓上。因此,第10層樓不是虛構的,而是確實存在的。如果對此有疑惑或者認為我在胡謅一番的話,那么不妨繼續往下看下去,窺一下第10層樓的秘密。

             

             第10層 大哲
            看了這層樓的名字“大哲”,可能不少人已經猜到了這層樓的秘密,那就是你的成果必須要上升到哲學的高度,你才有機會能進到這層來。

            當然,上升到哲學高度只是一個必要條件,牛頓的萬有引力似乎也上升到了哲學的高度,因為不知道引力到底是怎么來的,但是牛頓沒有被劃到這一層,因為進到這層還有另外的條件,那就是你的成果必須引起了哲學上的深度思考,并能讓人們的世界觀向前跨進一大步。竊以為牛頓、愛因斯坦等人的成就還達不到讓人們世界觀向前跨進一大步的程度。

            所以,這層樓中的人的成就對我們普通人認識世界非常重要,你可以不學相對論,但是你不可以不對這層樓的人所作出的成就不了解,否則你的世界觀就是極其不完整的,會犯許多認識上的錯誤。不幸的是,中國的科普知識普及還不夠到位,知道這層樓成就的人好像并不多,程序員中恐怕更少。下面就來看看這些用一只手的手指數得清的大哲們,到底有什么成就,能比萬有引力定律和相對論還重要。

            1、希爾伯特 (1862~1943)

            第1位進到此樓層是一位名叫“希爾伯特”的大數學家,如果你學過《泛函分析》,那么你在學習希爾伯特空間時可能已經對這位大數學家有所了解;如果你不是學數學出身的,又對數學史不感興趣的話,恐怕你從來沒有聽說過這個名字。不過如果我問一下,知不知道二次世界大戰前世界數學中心在那里,你肯定會有興趣想知道。

            不妨說一下,二戰前整個世界的數學中心就在德國的哥廷根,而我們這位大數學家希爾伯特便是它的統帥和靈魂人物。即使在二戰期間,希特勒和丘吉爾也有協定,德國不轟炸牛津和劍橋,作為回報,英國不轟炸海德堡和哥廷根。

            整個二十世紀上半期的超一流數學家,幾乎都出自其門下。這里不妨舉幾個我們熟悉的人物,例如馮·諾伊曼就曾受到他和他的學生施密特和外爾的思想影響,還到哥廷根大學任過希爾伯特的助手,錢學森的老師馮·卡門是在哥廷根取得博士學位的。順便提一下,這位大數學家發現當時物理學上出了很多大的成果如相對論和量子力學,但是這些物理學家的數學功力明顯不足,因此有一段時間帶領他的學生們研究過物理學,并獨立發現了廣義相對論,只是不好意思和物理學家爭功勞,將廣義相對論的功勞全部讓給了愛因斯坦。

            廣義相對論相對于這位大數學家在數學上的貢獻,其實是算不了什么的,只是由此可看出這位大數學家品格的高尚之處。如果再去看看牛頓之流的人物的品行,整天和萊布尼茨、虎克等人爭功勞,利用自己的優勢地位打壓他人,甚至鬧得上法庭,和這位希爾伯特先生比起來,簡直就是個小丑。

            說到這里,你可能對這位大數學家“希爾伯特”有了一些初步映象,感覺到了他的重要性,不過他在數學上的主要成就可不是幾句話說得清楚的。首先,他是一位集大成者,精通當時數學所有分支領域,在數學的各個領域都有較大的貢獻,當然這些成就只能讓他成為一個大科學家,不能帶他進入這層樓。事實上這位“希爾伯特”解決的任何一個數學問題都夠不到這層樓的高度,那么他怎么混到這層樓來了呢?

            話得從1900年說起,當時還很年輕的希爾伯特在當時的世界數學大會上做了一個報告,高屋建甌地提出了著名的23個未解決的數學問題,然后整個二十世紀上半期,全世界的數學家們都在這23個問題的指導下展開研究,直到現在仍然有許多數學家受這23個問題的指導在進行研究。例如我們熟知的哥德巴赫猜想,就屬于其中第8個問題素數分布的一個子問題。

            如果用“高瞻遠矚”來形容這位大數學家的話,那么這個世界上恐怕沒有第二個人再配得上“高瞻遠矚”這四個字,不論是歐拉、高斯、牛頓、愛因斯坦還是被譽為最有才華的數學家伽羅華,概不例外。

            雖然那23個問題是歸納總結出來的,并不全是原創,但是其中有不少問題是可以上升到哲學的高度,引起深度思考的。可能大多數人都會覺得希爾伯特是進不到這層樓的,我們知道提出問題的人和解決問題的人是一樣偉大的,何況他提出的問題是如此之多,基于這點,個人覺得應該讓希爾伯特跨進這層樓的門檻里。

            看完這位希爾伯特的成就,你可能會覺得對你的世界觀并沒有產生任何影響。確實如此,他提出的問題不是用來影響你的,而是用來影響其他大科學家和大哲的,下面再來說說另一位對他提出的23個問題中的第2個問題有杰出貢獻的大哲,你就會感覺到大哲們的成果的威力了。

            2、哥德爾 (1906~1978)

            這位大哲的名字叫“哥德爾 (Gödel) ”,你可能從來也沒有聽說過這個名字,即使你讀了一個數學系的博士學位,如果你的研究方向不和這位大哲對口的話,你也不一定了解這位大哲的成就,更不知道他的成果對我們這個世界有何意義。

            簡單地說,這位大哲20多歲時就證明了兩個定理,一個叫做“哥德爾完全性定理”,另一個更重要的叫做“哥德爾不完全性定理”。你也許會覺得奇怪,第9層樓的成就就已經上升到了公理的高度,這種證明定理的事情不是學者和大師們做的事情嗎?怎么能比第9層樓的成就還高呢?下面就來簡單說一下這兩個定理的含義,你就會明白這屬于系統級的定理,絕不是普通的定理和公理所能比擬的。

            “哥德爾完全性定理”證明了邏輯學的幾條公理是完備的,即任何一個由這些公理所產生出的問題,在這個公理系統內可以判定它是真的還是假的,這個結論表明了我們人類所擁有的邏輯思維能力是完備的。這條定理并不能將其帶入這層樓來,帶其進入這層樓的是另一條定理。

            “哥德爾不完全性定理”是在1930年證明的,它證明了現有數學的幾條公理(ZF公理系統)是不完備的,即由這些公理產生出的問題,無法由這幾條公理判斷它是真的還是假的。例如希爾伯特23個問題中的第1個問題,也就是著名的康托爾連續統假設,哥德爾在1938年證明了現有公理系統中不能證明它是“假”的,科恩(Cohen,或許也可以稱得上是“半”個大哲)在1963年證明了現有公理系統不能證明它是“真”的。最有趣的是,即使你將某個不可判定的問題,作為一條新的公理加入進去,所組成的新的公理系統仍然是不完備的,即你無法構造一個有限條公理的系統,讓這個公理系統是完備的。

            也許你仍然無法理解上面這段話的含義,不妨先說一下它對我們現實世界的影響。你可能知道1936年出現的圖靈機是現代計算機的理論模型,如果沒有哥德爾不完全性定理的思想,圖靈機什么時候能出來是很難說的,所以這位哥德爾可以算作計算機理論的奠基者的奠基者。計算機對我們這個世界產生的影響比原子彈大了多少,我想不用我說大家也都清楚。當然,對現實世界的影響只能把哥德爾同圖靈等人一樣劃到大科學家那一層去,能進入這層乃是另有原因。

            可能你看過《未來戰士》、《黑客帝國》、《I,Robot》之類的科幻電影,于是你產生制造一個和人一樣或者比人更高一級的智能機器人的想法,這就引入了一個達到哲學高度的問題,“人到底能不能制造出具有和人一樣的思維能力的機器來?”。

            我只能告訴你,“你的愿望是良好的,但現實是殘酷的”。如果你仔細思考一下不完全性定理的含義,并結合現代計算機所具有的能力分析一下,你會發現這個問題的答案暫時是否定的。如果你想造出和人一樣思維能力的機器,那么你需要去好好學習這位大哲及其后續研究者的成果,并在他們的基礎上有新的突破才行。

            為了說明這位大哲所研究領域的重要性,這里順便再討論一個我們日常爭議不休的問題,那就是孔夫子的“人之初、性本善”以及西方認為“人之初、性本惡”的觀點孰優孰劣的問題。可能有許多人發現西方社會現在領先我們,于是就認為“性本惡”是對的,“性本善”是錯的,中國應該拋棄以前的舊思想,改用西方的思想。當然也有一些老學究們,認為中國的人文思想是領先于西方的,自然而然地認為“性本善”是對的,“性本惡”是錯的。

            如果你學過大哲用過的公理化的分析方法,你就知道一套系統的多條公理間只要不會推導出矛盾的地方,即可以自圓其說,那么它可以看作是對的。這樣你可以很輕易地給這個問題下一個結論,即“性本善”和“性本惡”是對等的,不存在孰優孰劣的問題,更不存在誰對誰錯的問題。只要你不同時將“性本善”和“性本惡”放入一個系統內,那么是不會有問題的,甚至你也可以認為“人之初、既無善、亦無惡”,或者認為“人之初、部分善、部分惡”,都是可以自圓其說的,所以我們的老祖宗提出的思想并沒有問題,之所以落后乃是其他原因造成的。這個問題其實在高斯所處的時代就有了結論,那時有人提出了非歐幾何,即平行線公理問題,有人認為過一點可以作多條平行線,還有人認為平行線在無窮遠點是相交的,和歐氏幾何關于過一點只能作一條平行線的公理都是矛盾的,但是他們各自的系統內推導出的結論都是正確的。

            上面說的只是對哥德爾不完全性定理的一些粗淺解析,實際上如果深入思考一下它的含義的話,你會發現它對物理學等許多學科有重大影響,包含的道理實在是深刻,遠非一般的思想所能比擬,有興趣者不妨“google”或“百度”一下“哥德爾”。或許只有我們的老祖宗“老子”提出的哲學思想,深度可以有得一比。

            哥德爾不完全性定理也給那些認為科學是嚴謹的人當頭一棒,原來連數學這樣的純理論學科都是不嚴謹的,其他學科就更不用說了。

            至此,已經說完數學上的大哲,下面不妨再看看物理學上的大哲,物理學上好像只出過一位叫“海森堡”的大哲(注:由于本人對物理學不甚了解,不知道“霍金”夠不夠得上大哲的稱號)。
            3、海森堡 (1901~1976)

            海森堡這個名字相信沒有幾個人不知道的,大部分人在學習物理時都學過他的“測不準關系”,也就是因為這個“測不準關系”,海森堡爬到了第十層樓。

            如果你看過《時間簡史》和《霍金講演錄-黑洞、嬰兒宇宙及其他》,你也許已經了解測不準關系的威力,所以這里不想做過多的討論,只談一些和本土產生的哲學思想相關的東西。

            首先看看爭論了幾千年,并且現在仍然有人在爭論不休的“宿命論”問題。霍金認為,只要這個宇宙有一個初始狀態,粒子的運動是按照一定物理定律進行的(比如相對論、量子力學屬于這些物理定律的一部分),那么所有的粒子運動軌跡將是確定的,然后只要你承認唯物論,即精神是由物質決定的,那么宿命論就是“對”的。當然由于測不準關系的存在,對人而言,又是無法準確預測的,因此也可以將其看作是“不對”的。簡單的說,可以認為宿命論是“對”的是絕對的,宿命論是“不對”的是相對的。

            可能上面這段話你現在仍然難以理解,或許你又覺得你的命運并不是上天注定的,而是可以通過自己的努力可以改變的。我要告訴你的是,你在想什么也是事先已注定的,包括你在預測本身也是事先注定的,因為大腦思考問題最終是基本粒子運動的結果,而這些粒子的運動必然要遵循物理定律進行,所以你會不會努力,想不想努力,包括你在想你該不該努力這件事本身也是事先注定的。順便說一下,你現在正在看這篇文章,可能正在想這個宿命論問題值得懷疑,或者覺得寫得不夠好,準備砸個板磚上來;或者你在想這篇問題寫得有點意思,準備看完后轉給朋友看一看;又或者你看到這里,覺得很累了,準備休息一下;…;這些都是上天事先就注定的。從你自身的相對角度看,因為你事先不知道后來會發生什么,也可以認為不是事先注定的,可能這句話有些不好理解,不妨好好理解前面說過的公理化思想。

            如果你沒看過《霍金講演錄-黑洞、嬰兒宇宙及其他》,你可能會覺得很驚訝,宿命論歷來不都被認為是唯心論嗎,怎么由唯物論推導出了宿命論呢?現實就是這樣和你開了一個大的玩笑,不過這個玩笑也是事先注定的。如果你再仔細用公理化的方法思考一下唯物論和唯心論的矛盾性,就像前面分析性善論和性惡論一樣,你會發現唯物論、唯心論不一定就是沖突的,矛盾的雙方是可以統一的,只要你不要同時將唯物和唯心放進同一個系統中就行。

            當然也有聰明者仍然會懷疑宿命論問題的正確性,因為這里有一個前提條件,即宇宙要有一個初始狀態。宇宙有沒有初始狀態,我們并不知道啊,雖然有大爆炸學說,但那也只是假說而已,并沒有得到確證,有些人就認為宇宙是一直都存在的。這樣看來似乎你又有合理的理由在懷疑宿命論了,不過我仍然要告訴你,你現在在懷疑宿命論仍然是事先注定的,不相信的話就來看看下面的分析。

            雖然宇宙的初始狀態值得懷疑,但是這個宇宙至少已經存在了一段時間,這點我想是毋庸置疑的。我們可以在我們已知的宇宙存在的這段時間內,任意取一個時間點t0,那么在這個時間點t0上,所有的粒子都有一個運動狀態。在時間點t0之后的時間里,由于粒子運動是按照物理定律進行的,因此粒子運動軌跡由時間點t0的狀態決定。說白一點,如果取100年前的一個時間點作為t0,那么現在的所有粒子運動狀態100年前就已經確定了,如果取10000年前一個時間點作為t0,那么最近10000年內所有粒子運動的軌跡在10000年前就確定了,當然,你可以取更早的時間,比如100億年前的時間點。

            總之,現在你會發現宇宙有沒有初始狀態并不會影響宿命論的正確性,所以這個世界的一切都是注定的。只不過由于粒子間相互影響過于復雜,我們無法知道這些粒子的運動軌跡而已。當然,如果將測不準關系用上的話,那么就是這個運動軌跡對人來說是無法準確預測的,所以不妨開個玩笑:“算命先生經常算得不準大概是測不準關系的緣故吧”。

            如果你再深入思考一下測不準關系,你會發現這是一個測量系統的問題。由于宿命論的存在,這個世界本身實際上是確定的,是“準“的,之所以測不準乃是我們人類所具有的測量能力依賴于基本粒子造成的。所以我在前面說宿命論是“不對”的是相對的,它是相對于我們人類的測量能力而言的。根岑(Gentzen,曾任希爾伯特的助手)在一個更強的系統內證明了ZF系統內的問題都是可判定的,從一個側面說明這個世界本身是確定的。(注:它和哥德爾不完全性定理并不矛盾,由于數學上的復雜性,這里就不詳細解釋了)

            不妨再想想我們老祖宗提出的“是莊周夢見了蝴蝶?還是蝴蝶夢見了莊周?”,“風動?幡動?還是心動?”之類的問題,當然以前你都認為這是純粹的唯心主義,甚至認為是封建糟粕,但是如果結合測不準關系的內涵,再結合前面所說的公理化分析方法進行分析,估計你現在不敢輕易地下結論。

            也許到現在你仍然無法理解為什么把大哲們劃在了大科學家的上一層,你可能仍然覺得萬有引力、相對論等成果是最偉大的。下面就來談談為什么大哲比大科學家高一層。

            如果把人類在現有能力情況下,將來所能夠擁有的知識總集看成是一個集合A,人類現在已有的知識總集看成是集合B,顯然,集合B只是集合A的一個子集,并且是很小的一個子集。牛頓力學、相對論這些理論只能算作集合B里的一個子集,相對于集合A,只能算作是滄海一粟。 換句話說,在人類現有能力可做的事情集合中,牛頓力學和相對論等理論給出了詳細的辦法讓你可以做其中的一些事情,當然剩下的更多的事情是牛頓力學和相對論所無法解決的。

            哥德爾不完全性定理和測不準關系的意義在于,它指出集合A的范圍,即將人類現有能力發揮到極限的情況下,那些事情是你能做到的,那些是你不能做到的。當然,它并沒有給出具體的方法讓你去做你能做到的事情,它只是告訴我們我們人類現在發現的能力所能達到的極限。或許將來發現人類有其他新的未發現的能力,那么這個極限就被打破了。比如將來能發現不依賴于基本粒子的其他測量方法,并且測量過程中不會改變其他粒子的狀態,那么測不準關系就被打破了。

            看到這里,估計你已經發現了一些秘密,科學兜了一大圈,最終還是回到了哲學,也就是我們所認為的玄學上。同時你也會發現,我們老祖宗提出的所謂玄學,原來和現代科學是相通的,并非象某些人想像的那樣全是糟粕。如果有人認為西方現代暫時領先我們,進而就認為西方古代就已經超越我們,我們老祖宗就已經落后西方,他們的思想都是糟粕的話,那么我認為他可能犯了崇洋媚外的毛病。我不得不化用一句周杰倫在春晚上的歌詞送給他:“你不妨抓一副我們祖傳的中醫良方,治一治你那崇洋媚外的內傷”。順便告訴他一下,中醫用的陰陽五行理論,它的前提假設就是宿命論。

            上面說的這幾位大哲的成果,可能對你的世界觀會有很大的影響,于是你可能會羨慕起這些大哲們的成果來。如果你有大志的話,你會希望有朝一日你也能變成大哲,但是你發現上面的大哲是研究數學和物理學的,而你是學計算機的程序員,那么是不是沒有機會變成大哲呢?

            如果你能將NP難題給徹底解決掉,意味著計算機內的計算的奧秘基本被揭開,或許你可以進到這層樓來;或者你能發現另外一套計算機可以理解的數學公理系統,并且這個公理系統是完備的,那么計算機取代人類進行思維的一個必要條件就滿足了,計算機將具有真正意義上的“邏輯思維和推理能力”,你可以輕松地進到這層樓來。如果你發現了新的方法可以打破測不準關系,同樣你也可以輕松地進到這層樓來。

            如果你能徹底揭開人類抽象思維的奧妙,并讓計算機懂得了如何創建抽象,具備抽象思維能力,那么也就具備了“設計能力”,可以取代人類進行各種設計了,你也可以輕松地進到這層樓來。順便說一下,如果你對軟件設計有真正深刻理解的話,就會明白這不是在寫科幻小說。對此感興趣者,不妨好好地研究一下程序切片方面的技術,會讓你對軟件設計和測試等方面的理解有質的提高,或許有一天你能打開這扇大門。

            當然,計算機要完全取代人還有其他必要條件,后面還會提及。

            值得一提的是,雖然第10層樓是本文中所寫的最高層,但是大哲們并沒有覺得他們到了頂層,他們通常都還會努力尋找通往更高一層的樓梯。如果你也有成為天下第一的想法,那么你或許會想要做什么事情才能超越大哲們的成就,當然,這都得依賴于找到更高一層樓的樓梯。

            個人認為,再往上一層樓的樓梯是通往天堂的道路,也就是說第11層樓的名字叫“天堂”,是“上帝”住的地方,而不是人住的地方。如果將來某天有人能爬到天堂的話,那么他已經不是人了,而是由人變成了“上帝”。

            你也許會懷疑這個世界到底有沒有“天堂”,“上帝”是否根本就不存在,我也很有同感。因此有必要再寫上一段文字,討論一下“上帝”的問題。如果你想了解天堂的奧妙,有沒有辦法讓你變成“上帝”,不妨看看繼續往下看看第11層樓的玄妙。注意我這里用的是“玄妙”二字,因為上帝在大部分人眼里估計都是“玄之又玄”的東西。


            第11層 上帝
            看了上面的小標題,你可能會覺得奇怪,這篇文章不是講“程序員的十層樓”嗎?怎么冒出了第11層來了?

            其實這并不矛盾,程序員確實只有十層樓,因為爬到第11層時,已經變成上帝,不再是程序員了;所以超出10層樓本身并不重要,關鍵的問題是看你有沒有能力變成上帝。

            1、誰是上帝?

            菜鳥們認為Linus Torvalds是程序員中的上帝,看完了前面各層樓的介紹,此時再看到這句話,相信你要忍不住在心里笑起來。當然,你會不會笑起來是事先注定的。Don Knuth也不是上帝,他離上帝還有三層樓的距離。即使是大哲們,他們離天堂也還差一層樓,因此這個世界上有史以來還沒有任何一個人變成過上帝。

            我們感興趣的是,將來會不會有人爬到比大哲們更高的樓層上,變成了上帝。

            要變成上帝,你得有上帝一樣的能力,上帝會造人,你會嗎?

            你也許會怯生生地問:“我可以和愛人生小孩,算不算造人?”,你可能還會理直氣壯地說:“現在生物學上都可以克隆人了,早就有人掌握了造人的方法”。

            事實上克隆人需要有人的體細胞,必須要先有人才會有體細胞。上帝造人時,這個世界上并沒有人,是從無生命的物質“塵土”中創造出的人。因此,用最原始的方法生人和克隆人都是從有生命信息的物質中生人,不能算作造人。

            這樣看來,你根本不會造人,不過我可以告訴你一個“玄方”,讓你有機會學會如何造人。

            如果你揭開了人類情感的奧秘,讓計算機也可以擁有和人類一樣的情感,那么計算機將可以理解人類的需求,具有了“情商”,將具有完整的和人一樣的能力。此時,人類進化到了機器人,科幻小說將變成現實,也就是說你已經掌握了真正的造人能力,晉升為“上帝”了。

            未來到底有沒有人能變成“上帝”,人能不能進化到機器人,這是宿命論中事先注定了的。說到這里,不妨再告訴你一個打破宿命論的方法,這個方法就是你要爬到比上帝還要高的樓層。

            “還有比上帝還高的樓層?”,你可能會第1時間內冒出這個問題,其實我也有同樣的懷疑。因此在寫第12層樓前,有必要弄清楚它到底存不存在,即你可不可以騎到上帝的頭上的問題。

            2. 騎到上帝的頭上?

            為了解決是否可以騎到上帝的頭上這個問題,不妨先假設存在比上帝高的樓層,也就是存在打破宿命論的方法。

            宿命論的本質原因是因為時間是單向運行,不可逆轉造成的。如果你找到一種可以使時間逆轉的方法,那么你就打破了宿命論,爬到了比上帝還高的樓層。

            看到這里,你也許會擺脫剛才陷于宿命論的困惑情緒,變得充滿希望般高興起來。不過,如果你的邏輯思維能力足夠好,仔細思考一下,會發現存在一個邏輯上的悖論。

            在你找到時間逆轉的方法之前,顯然這個世界仍然是需要服從宿命論的,也就是說你能不能找到打破宿命論的方法是事先注定的。假設你在某個時間點t0處找到了打破宿命論的方法,你在打破宿命論后,想利用時間逆轉的方法回到某個時間點t2。下面來看看你到底能不能回到時間點t2。

            取位于t0和t2之間的任意一個時間點t1,你在回到時間點t2之前,必須先經過時間點t1,考慮你到達t1的那一時刻,由于t1比t0要早,這個時間點上你還沒有找到時間逆轉的方法,所以到了時間t1點后,你無法再使用時間逆轉的能力回到時間點t2去,所以你永遠也回不到時間點t2,由于時間點t2是任意取的,因此,你永遠也無法使時間逆轉,或者說你根本就沒打破過宿命論,這與你在時間點t0打破了宿命論產生了矛盾。

            上面這段話看起來似乎有點像“人永遠邁不出一步”的詭辯一樣,你可能會想返回到時間點t1時,仍然可以擁有時間逆轉能力啊。不過你又會發現一個新的問題,時間點t1本來是沒有時間逆轉能力的,現在又認為時間點t1又有時間逆轉能力,那時間點t1到底是有還是沒有時間逆轉能力呢?或者說在時間點t0前,宿命論注定了時間點t1是沒有時間逆轉能力的,現在你又認為時間點t1具有時間逆轉能力,那么這兩個時間點t1究竟是不是同一個時間點?如果不是同一個時間點,說明你沒有回到過去;如果是同一個時間點的話,豈不是自相矛盾嗎?

            為了說得更形象一些,不妨假設你坐一艘超光速飛船,準備從時間點t0回到時間點t2去,假設你回到t2后,隨著時間的流逝,又達到了時間點t0,如果這時你又再次坐超光速飛船返回時間點t2,那么一個值得思考的問題就出現了,“你在時間點t2能不能看到上次返回時間點t2的飛船?”

            如果回答不能看到飛船,那么上次返回的飛船那里去了呢?顯然很難解釋通。如果回答能看到飛船,那么你可以到達時間點t2后,下次時間到達t0時,你又坐飛船返回t2,這次你將可以看到上兩次的兩艘飛船。如果這樣一直循環下去,最后你會發現你可以在時間點t2看到無窮多的飛船。用程序員的術語說,叫做“程序陷入了死循環”,最后系統必然會出現“Out of Memory”現象而崩潰。

            當然,你也可以認為有其他的方法,不需要飛船,可以一次性從時間點t0直接跳躍到時間點t2,并不需要經過時間點t1。下面不妨來分析一下這個方法是否可行。

            既然是直接跳躍到時間點t2,那么你必然是在一個無窮小的時間里出現在時間點t2的某個空間里,例如你要在時間點t2回到某個廣場上。首先說明一下為什么是無窮小的時間里出現的,因為如果不是無窮小的時間里出現的話,那么必然可以取到一個時間點t1,會導致前面所說的時間點t1上出現悖論。

            你在廣場上出現的時,廣場上的空氣必然要為你讓開空間,而這是在無窮小的時間里完成的,那么很容易推導出你周圍的空氣獲得的加速度和速度都是無窮大,因而它具有的動能也是無窮大,無窮大的能量和無窮大的速度意味著什么?一只鳥都可以將飛機撞下來,如果宇宙是有限大的話,它可以讓這個宇宙炸毀無窮次;即使宇宙是無限大,它也足以讓宇宙炸毀一次。宇宙都毀滅了,又何來的時間?還能說你回到了時間點t2嗎?

            也許上面說的這些你仍然難以相信,不妨再說得更現實一些,假設你要回到100年前的一個時間點,這100年中,天上有多少流星湮滅了?有多少新星生成了?宇宙膨脹了多少?你有能力讓湮滅的流星復原、生成的新星重新返回未生成前的狀態,膨脹的宇宙收縮回去嗎?如果這些東西的狀態沒有回復到100年前,又怎么能說明你回到的是100年前的時間點呢?

            根據上面的推導和分析,個人認為使時間逆轉的方法是不存在的,所以第12層樓是不存在的,自然沒有人可以騎到“上帝”的頭上。

            宿命論將在有時間的時間里永遠統治這個世界。

             

            本文來自CSDN博客,轉載請標明出處:http://blog.csdn.net/xjbx/archive/2009/02/08/3869314.aspx

            posted @ 2010-02-20 15:18 糯米 閱讀(339) | 評論 (0)編輯 收藏

            POJ 1945 Power Hungry Cows 終極打表

            這道題是一道智力題
            所以想了n久,都想不出什么“數學方法”。甚至都想不出什么比較好的剪枝方法。
            測了一下,普通的bfs比較慢。算到18步就開始就龜速了。
            要算到21步才能得出1~20000的每一個答案。然而算到21步,在T8100 cpu的本本上都要跑半分鐘,囧。。
            所以沒辦法了,只能打表了。看了一下status。發現排在第一頁的人打表的不少呢!哈哈。

            但是問題來了。20000大小的數組,每個元素在1~21之間,如果這樣表示出來
            int arr = {1, 2, 3, ....}
            那不得40k+左右嗎。顯然poj是不允許提交這么大的代碼的!
            但是status里面那些打表的人,代碼都在20k~30k左右。這是怎么回事呢?
            我有點懷疑別人看了答案,呵呵。但又不排除有方法能把代碼長度控制好。
            所以,考慮了下面幾個方法:


            1. 元素的范圍是在 1~21 之間。所以要盡量用4bit表示一個元素。
            統計了下,發現16以上的元素占了70%左右。所以規定:
            >=16的元素,表示為 u4 arr[] = { (val&0xf) + 1 } 占用4bit
            < 16的元素,表示為 u4 arr[] = { 0, val } 占用8bit
            將它稱之為"halfbyte"壓縮
            2. 霍夫曼壓縮,lz77壓縮
            3. base64編碼

            這兩天實在是閑的蛋疼。于是就把這個幾個玩意寫了一下。
            經過測試,發現用 lz77 是獲得的代碼長度是最短的!僅9k!
            統計如下:

            === generate: e:\test\1945_base64.cpp
            base64 encode: 20032 -> 26712 133.35%
            total: 20032 -> 26712 133.35%
            file size: 27.22K

            === generate: e:\test\1945_halfbyte_base64.cpp
            halfbyte encode: 20032 -> 11842 59.12%
            base64 encode: 11842 -> 15792 133.36%
            total: 20032 -> 15792 78.83%
            file size: 17.15K

            === generate: e:\test\1945_halfbyte_huffman_base64.cpp
            halfbyte encode: 20032 -> 11842 59.12%
            huffman encode: 11842 -> 5964 50.36%
            base64 encode: 5964 -> 7952 133.33%
            total: 20032 -> 7952 39.70%
            file size: 11.42K

            === generate: e:\test\1945_halfbyte_huffman_lz77_base64.cpp
            halfbyte encode: 20032 -> 11842 59.12%
            huffman encode: 11842 -> 5964 50.36%
            lz77 encode: 5964 -> 8838 148.19%
            base64 encode: 8838 -> 11784 133.33%
            total: 20032 -> 11784 58.83%
            file size: 15.78K

            === generate: e:\test\1945_huffman_base64.cpp
            huffman encode: 20032 -> 6644 33.17%
            base64 encode: 6644 -> 8860 133.35%
            total: 20032 -> 8860 44.23%
            file size: 11.71K

            === generate: e:\test\1945_huffman_lz77_base64.cpp
            huffman encode: 20032 -> 6644 33.17%
            lz77 encode: 6644 -> 8097 121.87%
            base64 encode: 8097 -> 10796 133.33%
            total: 20032 -> 10796 53.89%
            file size: 14.21K

            === generate: e:\test\1945_lz77_base64.cpp
            lz77 encode: 20032 -> 5422 27.07%
            base64 encode: 5422 -> 7232 133.38%
            total: 20032 -> 7232 36.10%
            file size: 8.81K

            所有方法都是0~32ms AC。
            呵呵,代碼太長了,就不貼了,給個下載:

            /Files/varg-vikernes/1945.rar

            posted @ 2010-02-18 16:53 糯米 閱讀(2798) | 評論 (2)編輯 收藏

            POJ 2187 Beauty Contest 凸包直徑

                 摘要: 題目大意:給一堆點,求直線距離最遠的兩個點。思路:就是求“凸多邊形的直徑”。google一下,很多結果的啦。首先要求出凸包,然后用一個比較牛逼的算法貌似可以在O(N)時間內求出凸包直徑。但是那算法太復雜啦,看了半天都看不懂,所以就枚舉凸包每兩個點之間的距離了。還是能200+ms過,因為凸包求出來以后,N就大大減小了。#include <stdio.h>...  閱讀全文

            posted @ 2010-02-16 14:05 糯米 閱讀(445) | 評論 (0)編輯 收藏

            POJ 2184 Cow Exhibition 背包

            題目大意:
            有100頭牛,每頭牛有Fi, Si兩個值。Fi, Si 范圍是-1000~1000
            選出一些牛,確保這些牛的 Sum{Fi} + Sum{Si} 最大 
            同時 Sum{Fi},Sum{Si} 都不能為負

            思路:
            一開始看到范圍那么大,首先就否決背包了!想了一個不大靈光的解法,結果wa啦。。
            后來看了Discuss。發現都是用背包過的,是最簡單的一維背包!居然還有人是搜索過的!
            但是,如果數據bt點的話,背包是不可能過的!但是USACO的題目感覺數據都弱一點,哈哈!

            代碼爛,63ms

            #include <stdio.h>

            struct {
                
            int val, used;
            }
             _slot[100024*2], *slot = &_slot[100024];
            int up, down;

            int main()
            {
                
            int n, s, f, i;

                freopen(
            "e:\\test\\in.txt""r", stdin);

                scanf(
            "%d"&n);
                up 
            = down = 0;
                
            while (n--{
                    scanf(
            "%d%d"&s, &f);
                    
            if (s < 0 && f < 0)
                        
            continue;
                    
            if (s < 0{
                        
            for (i = down; i <= up; i++{
                            
            if (!slot[i].used)
                                
            continue;
                            
            if (!slot[i + s].used || f + slot[i].val > slot[i + s].val) {
                                slot[i 
            + s].used = 1;
                                slot[i 
            + s].val = f + slot[i].val;
                            }

                        }

                        down 
            += s;
                    }
             else {
                        
            for (i = up; i >= down; i--{
                            
            if (!slot[i].used)
                                
            continue;
                            
            if (!slot[i + s].used || f + slot[i].val > slot[i + s].val) {
                                slot[i 
            + s].used = 1;
                                slot[i 
            + s].val = f + slot[i].val;
                            }

                        }

                        up 
            += s;
                    }

                    
            if (!slot[s].used || slot[s].val < f) {
                        slot[s].used 
            = 1;
                        slot[s].val 
            = f;
                    }

                }


                s 
            = 0;
                
            for (i = 0; i <= up; i++{
                    
            if (slot[i].used && slot[i].val >= 0 && slot[i].val + i > s)
                        s 
            = slot[i].val + i;
                }

                printf(
            "%d\n", s);
                
                
            return 0;
            }


            posted @ 2010-02-16 10:59 糯米 閱讀(842) | 評論 (0)編輯 收藏

            POJ 3670 Eating Together 動態規劃

            題目大意:
            給出一個序列,序列里的數字都是1~3,比如:
            1 3 2 1 1
            你可以改變任意一個數字。
            問:最少改變多少次,能使序列變成升序序列或者降序序列。
            比如第一個1改成3,使它變成 3 3 2 1 1,就變成降序序列了。

            思路:
            從后往前推,先考慮變成升序序列的情況。
            定義:
            f[3][i] = 最后一個元素到第i個元素全部改變為3所需要的次數
            f[2][i] = 最后一個元素到第i個元素改變為22222...33333...所需要的最小次數
            f[1][i] = 最后一個元素到第i個元素改變為11111...22222...33333所需要的最小次數
            那么 f[1][1] 就是答案了。
            可見,對于第i個元素:
            f[3]很容易計算出來
            f[2] = min{ f[3][i-1], (第i個元素 == 2) + f[2][i-1] }
            f[1] = min{ f[2][i-1], (第i個元素 == 1) + f[1][i-1] }
            那么復雜度就是 O(N) 了。降序序列一樣處理,從前往后推。

            優化:
            輸入序列里面的一長串一樣的元素可以一段一段處理
            f數組可以變成滾動數組

            代碼:
            這個算法應該還算可以的,看到Disscuss里面有人說用“最長不降子序列”來做,還不知道用那個怎么做。。
            最長不降子序列,好像求出長度的貪心算法是 O(NlgN),求出序列的動規算法是 O(N^2)。
            但是好像那些人提交的代碼都挺快的,0ms
            我的代碼比較爛,32ms。。想不通啊。。


            #include <stdio.h>
            #include 
            <string.h>

            struct {
                
            int val, len;
            }
             in[30024];
            int in_cnt;
            int num_cnt[4], f[4][2];

            __inline 
            int min(int a, int b)
            {
                
            return a < b ? a : b;
            }



            int main()
            {
                
            int i, n, val, a, b;

                freopen(
            "e:\\test\\in.txt""r", stdin);

                scanf(
            "%d"&n);
                
            for (i = 0; i < n; i++{
                    scanf(
            "%d"&val);
                    
            if (val != in[in_cnt].val) 
                        
            in[++in_cnt].val = val;
                    
            in[in_cnt].len++;
                }


                
            for (i = in_cnt; i >= 1; i--{
                    num_cnt[
            in[i].val] += in[i].len;
                    f[
            3][i&1= num_cnt[2+ num_cnt[1];
                    f[
            2][i&1= min(f[3][i&1], (in[i].val!=2)*in[i].len + f[2][(i-1)&1]);
                    f[
            1][i&1= min(f[2][i&1], (in[i].val!=1)*in[i].len + f[1][(i-1)&1]);
                }

                a 
            = f[1][(i-1)&1];

                memset(num_cnt, 
            0sizeof(num_cnt));
                memset(f, 
            0sizeof(f));
                
            for (i = 1; i <= in_cnt; i++{
                    num_cnt[
            in[i].val] += in[i].len;
                    f[
            3][i&1= num_cnt[2+ num_cnt[1];
                    f[
            2][i&1= min(f[3][i&1], (in[i].val!=2)*in[i].len + f[2][(i-1)&1]);
                    f[
            1][i&1= min(f[2][i&1], (in[i].val!=1)*in[i].len + f[1][(i-1)&1]);
                }

                b 
            = f[1][(i-1)&1];

                printf(
            "%d\n", min(a, b));

                
            return 0;
            }




            posted @ 2010-02-15 10:29 糯米 閱讀(470) | 評論 (0)編輯 收藏

            POJ 3668 Game of Lines 哈希

            題目大意:
            給出n個點,問你最多能連多少條線,保證這些線都不平行

            思路:
            計算每兩點斜率,用分數的形式表示,然后哈希判重。要考慮斜率不存在和斜率為0的情況

            #include <stdio.h>

            int hash[2][2024][2064/32], hori, vert;
            struct node {
                
            int x, y;
            }
             points[256];
            int N, line_cnt;

            __inline 
            int gcd(int a, int b)
            {
                
            int r;

                
            if (a < b) {
                    r 
            = a;
                    a 
            = b;
                    b 
            = r;
                }


                
            while (1{
                    r 
            = a % b;
                    
            if (!r)
                        
            return b;
                    a 
            = b;
                    b 
            = r;
                }

            }


            __inline 
            int test_bit(int *arr, int idx)
            {
                
            return arr[idx >> 5& (1 << (idx & 0x1f));
            }


            __inline 
            int set_bit(int *arr, int idx)
            {
                
            return arr[idx >> 5|= (1 << (idx & 0x1f));
            }


            __inline 
            int abs(int i)
            {
                
            return i < 0 ? -i : i;
            }


            __inline 
            void gril(struct node *pa, struct node *pb)
            {
                
            int dx, dy, neg, r;

                dx 
            = pa->- pb->x;
                dy 
            = pa->- pb->y;
                
            if (!dx) {
                    
            if (vert)
                        
            return ;
                    vert 
            = 1;
                    line_cnt
            ++;
                    
            return ;
                }

                
            if (!dy) {
                    
            if (hori)
                        
            return ;
                    hori 
            = 1;
                    line_cnt
            ++;
                    
            return ;
                }

                neg 
            = dx*dy < 0;
                dx 
            = abs(dx);
                dy 
            = abs(dy);
                r 
            = gcd(dx, dy);
                dx 
            /= r;
                dy 
            /= r;
                
            if (test_bit(hash[neg][dx], dy))
                    
            return ;

                set_bit(hash[neg][dx], dy);
                line_cnt
            ++;
            }


            int main()
            {
                
            int i, j;

                freopen(
            "e:\\test\\in.txt""r", stdin);

                scanf(
            "%d"&N);
                
            for (i = 0; i < N; i++
                    scanf(
            "%d%d"&points[i].x, &points[i].y);

                
            for (i = 0; i < N - 1; i++{
                    
            for (j = i + 1; j < N; j++{
                        gril(
            &points[i], &points[j]);
                    }

                }

                printf(
            "%d\n", line_cnt);

                
            return 0;
            }

            posted @ 2010-02-14 22:29 糯米 閱讀(441) | 評論 (0)編輯 收藏

            POJ 3669 Meteor Shower 寬搜

            題目大意:
            一個杯具男在地上躲隕石。用坐標軸的第一象限表示他的位置。
            初始時刻他位于坐標軸原點。單位時間內他只能移動一格。
            有很多塊隕石在不同時刻砸下來,隕石砸的時候會把上下左右和中間的格子砸壞。
            格子一旦砸壞了就不能再經過了。
            問,杯具男要怎么走才能在最短時間內走到一個安全地點---隕石不會落下的地方。

            思路:
            BFS搜索。如果走到某個地方,發現隕石已經掉下來了,就不繼續走了。很常規的思路,呵呵。
            代碼速度還行。根據排行來看~

            注意:
            Disscuss里有人說,此題數組要開到400。

            #include <stdio.h>

            int map[450][450];
            char visited[450][450];

            struct node {
                
            struct {
                    
            int x, y;
                }
             arr[8192];
                
            int cnt;
            }
             _queue[2], *cur, *nxt;

            __inline 
            int in_range(int x, int y)
            {
                
            return !(x < 0 || y < 0);
            }


            __inline 
            void insert(struct node *n, int x, int y)
            {
                
            if (!in_range(x, y) || visited[x][y])
                    
            return ;
                n
            ->arr[n->cnt].x = x;
                n
            ->arr[n->cnt].y = y;
                visited[x][y] 
            = 1;
                n
            ->cnt++;
            }


            __inline 
            void crash(int x, int y, int t)
            {
                
            if (!in_range(x, y))
                    
            return ;
                
            if (!map[x][y] || t + 1 < map[x][y])
                    map[x][y] 
            = t + 1;
            }


            int solve()
            {
                
            int x, y, step, i, t;

                _queue[
            0].cnt = 1;
                visited[
            0][0= 1;
                
            for (step = 0; ; step++{
                    cur 
            = &_queue[step & 1];
                    nxt 
            = &_queue[(step + 1& 1];
                    
            if (!cur->cnt)
                        
            return -1;
                    nxt
            ->cnt = 0;
                    
            for (i = 0; i < cur->cnt; i++{
                        x 
            = cur->arr[i].x;
                        y 
            = cur->arr[i].y;
                        t 
            = map[x][y];
                        
            if (!t) {
                            
            //printf("step %d (%d,%d) %d\n", step, x, y, t);
                            return step;
                        }

                        
            if (step + 1 >= t)
                            
            continue;
                        
            //printf("step %d (%d,%d) %d\n", step, x, y, t);
                        insert(nxt, x - 1, y);
                        insert(nxt, x 
            + 1, y);
                        insert(nxt, x, y 
            + 1);
                        insert(nxt, x, y 
            - 1);
                    }

                }

            }


            int main()
            {
                
            int m, x, y, t;

                freopen(
            "e:\\test\\in.txt""r", stdin);

                scanf(
            "%d"&m);
                
            while (m--{
                    scanf(
            "%d%d%d"&x, &y, &t);
                    crash(x, y, t);
                    crash(x 
            + 1, y, t);
                    crash(x 
            - 1, y, t);
                    crash(x, y 
            + 1, t);
                    crash(x, y 
            - 1, t);
                }

                printf(
            "%d\n", solve());

                
            return 0;
            }

            posted @ 2010-02-14 21:08 糯米 閱讀(1360) | 評論 (0)編輯 收藏

            POJ 3740 Easy Finding 剪枝+位操作

            題目大意:
            Given a M×N matrix A. Aij ∈ {0, 1} (0 ≤ i < M, 0 ≤ j < N), could you find some rows that let every cloumn contains and only contains one 1.


            代碼寫得不好看,速度一般,200+ms
            #include <stdio.h>
            #include 
            <string.h>

            int M, N, T;
            unsigned 
            short arr[320];

            int dfs(int idx, unsigned short ban, unsigned short sel)
            {
                
            int i;
                unsigned 
            short mask;

                
            if (idx == N)
                    
            return 1;

                mask 
            = sel & arr[idx];
                
            if (mask & (mask - 1))
                    
            return 0;
                
            if (mask)
                    
            return dfs(idx + 1, (ban | arr[idx]) & ~mask, sel);

                
            for (i = 0; i < M; i++{
                    mask 
            = 1 << i;
                    
            if (ban & mask)
                        
            continue;
                    
            if (!(arr[idx] & mask))
                        
            continue;
                    
            if (dfs(idx + 1, (ban | arr[idx]) & ~mask, sel | mask))
                        
            return 1;
                }


                
            return 0;
            }


            int main()
            {
                
            int i, n, m;

                freopen(
            "e:\\test\\in.txt""r", stdin);

                
            while (scanf("%d%d"&M, &N) != EOF) {
                    memset(arr, 
            0, N*2);
                    
            for (m = 0; m < M; m++{
                        
            for (n = 0; n < N; n++{
                            scanf(
            "%d"&i);
                            
            if (i)
                                arr[n] 
            |= 1 << m;
                        }

                    }

                    printf(dfs(
            000? "Yes, I found it\n" : "It is impossible\n");
                }


                
            return 0;
            }

            posted @ 2010-02-14 16:23 糯米 閱讀(267) | 評論 (0)編輯 收藏

            POJ 1063 Flip and Shift 智力題

            一個小游戲。挺好玩的。
            http://acm.pku.edu.cn/JudgeOnline/problem?id=1063

            flip 和 shift 兩種操作結合起來可以將任意的黑子向任意方向移動偶數步。

            分兩種情況:


            1.有奇數個槽時:
            位于奇數位置的黑子也可以移動到偶數位置中,因為可以兩個方向移動。
            所以可以將任意黑子移動到任意位置。
            所以無論什么情況都能達到goal

            2.有偶數個槽時:
            位于奇數位置的黑子永遠位于奇數位置
            位于偶數位置的黑子永遠位于偶數位置
            所以奇數位置的黑子和偶數位置的黑子相差1的時候可以達到goal


            #include <stdio.h>
            #include 
            <math.h>

            int main()
            {
                
            int t, n, i, j, arr[2];

                freopen(
            "e:\\test\\in.txt""r", stdin);

                scanf(
            "%d"&t);
                
            while (t--{
                    scanf(
            "%d"&n);
                    arr[
            0= arr[1= 0;
                    
            for (i = 0; i < n; i++{
                        scanf(
            "%d"&j);
                        arr[i 
            & 1+= j;
                    }

                    printf(
            "%s\n", (n & 1|| abs(arr[0- arr[1]) <= 1 ? "YES" : "NO");
                }


                
            return 0;
            }



            posted @ 2010-02-14 01:12 糯米 閱讀(455) | 評論 (0)編輯 收藏

            僅列出標題
            共17頁: First 9 10 11 12 13 14 15 16 17 
            亚洲国产高清精品线久久| 久久九九精品99国产精品| 午夜精品久久久内射近拍高清| 久久精品国产亚洲av麻豆蜜芽| 色欲久久久天天天综合网| 2021久久精品国产99国产精品| 久久久久久亚洲精品无码| 亚洲精品午夜国产VA久久成人| 一级做a爰片久久毛片人呢| 国产aⅴ激情无码久久| 久久亚洲高清观看| 亚洲国产精品无码久久| 精品水蜜桃久久久久久久| 久久精品国产精品亚洲毛片| 色欲综合久久躁天天躁| 曰曰摸天天摸人人看久久久| 国色天香久久久久久久小说| 久久se精品一区精品二区国产| 精品久久久噜噜噜久久久| 精品久久久久久久国产潘金莲| 国产—久久香蕉国产线看观看| 久久99久久99精品免视看动漫| 亚洲午夜无码久久久久小说| 国内精品久久久久久久久| 九九精品99久久久香蕉| 久久99久久99精品免视看动漫| 色综合合久久天天给综看| 国产69精品久久久久9999| 大伊人青草狠狠久久| 亚洲午夜久久久久妓女影院 | 久久天天躁狠狠躁夜夜96流白浆 | 久久国产色AV免费看| 精品综合久久久久久98| 久久夜色精品国产噜噜亚洲a| 亚洲а∨天堂久久精品9966| 久久男人中文字幕资源站| 久久这里只有精品久久| 国产成人99久久亚洲综合精品 | 91久久香蕉国产熟女线看| 久久精品99久久香蕉国产色戒 | 久久免费精品一区二区|