[Acm] 开始你的ACM-ICPC之旅(转)
我覺得這樣的文章應該有人寫過的,但是Google里面貌似沒有(或許有英文版)
Baidu給了一個,不過不是很像樣http://baike.baidu.com/view/94274.htm
那我就寫一個吧,這也是momodi大牛在上個學期初委托給我的一件事情。
這篇文章面向的對象是沒有多少基礎,或者是才學C語言或數據結構的同鞋們。
--
首先,什么是acm/icpc?ACM/ICPC(ACM International Collegiate Programming Contest, 國際大學生程序設計競賽)是由國際計算機界歷史悠久、頗具權威性的組織ACM(Association for Computing Machinery,國際計算機協會)主辦的,世界上公認的規模最大、水平最高的國際大學生程序設計競賽。
——這段定義來自 百度百科 -> ACM/ICPC,其實說簡單了就幾個字:想算法,寫程序,解題目。
雖然要先想算法(解決問題的有效辦法),但是如果不會寫程序,想出來的算法通常會馬頭不對牛嘴:因為你的腦子不是電動的,不是用電腦的方式去思考怎樣解決問題,通常這并不能有效地轉化為計算機語言源程序(當然,不是說學會了寫程序你的腦子就是電動的了)。寫程序的過程,其實就是把人腦當電腦去和電腦說話,讓它能夠明白它要作的事情。所以,廢話總結了就是,要先學計算機語言,這樣你才可以和計算機打交道,讓它去解決你想解決的問題。
acm/icpc正式比賽支持3種計算機語言,它們分別是c, c++, java。對pascal的支持已經被取消,但是大多數在線評測系統仍然支持pascal。如果沒有學過計算機語言,那么你需要挑其中一種開始;所以如果你學過其中某一種語言,馬上就可以開始了。不過,無論會或不會,這里仍然建議學習C++。C++是C語言的徒弟,不但學會了C語言的靈活性,還有自創了很多新功夫以方便程序員,比如面向對象機制、STL(標準模板庫)等。另外,java也是值得學習的,因為它C++的徒弟,雖然笨了一點,但是它是完全的面向對象語言,還有一些C++沒有自創的功夫,比如說BigInt(高精度整數類),如果用C++來實現,需要多寫數百行代碼(如果題目要開方,你就哭去吧),但是在java里面,只需要簡單的一個import以后就可以使用了。
學習計算機語言,其實很簡單——寫來寫去就那幾個單詞阿,泡MM還不知道得學多少花言巧語呢,所以,把電腦當MM來泡,嗯。這是一個轉變你思考問題方式的過程,甚至對你處事方式都會有很大的影響。下面以c/c++為例展開。
找一本好書開始,是非常有必要的(因為上補習班很貴,嘿嘿)。雖然上面推薦學習C++,但是不妨從C語言入手,因為C會的功夫最少,入門最快(C++的秘籍里面總有很多讓新手眼花繚亂、匪夷所思的詞語),但是濃縮就是精華,想學[精]C的功夫,也不容易。這里推薦的是清華大學出版社 譚浩強老師的《C程序設計》(已經有第三版了)。有了一本好書,就可以開始了。
然后給自己找一個舒服的寫代碼的軟件,通常我們叫它 IDE, Integrated Development Environment,集成開發環境。初學者當然會想找一個容易快速上手的IDE,那么這里推薦Devcpp,輕巧免費(免費!)易用,當然,微軟的Visual Studio也是很不錯的,它的調試功能很強大,設計也比較人性化,不過就是老掉牙的VC6有點不夠符合C/C++的標準(VC2005以上OK了)——而且也忒貴了一點(順便說一下M$的DreamSpark計劃,可以讓學生免費使用正版Visual Studio 2008,詳情百度一下)。如果你有挑戰自己的信心,那么最好的解決方案無疑是用最NB的[Vim/Emacs] + [gcc/g++]。vim和emacs都是強大的編輯器,搭配上同樣開源免費的gcc/g++編譯器,在熟練使用以后,能夠明顯提高你編碼的速度(有一種說法是,世界上的程序員分三種:一種使用Emacs,一種使用Vim,第三種使用其它編輯器)。然后你可以打開教材,翻翻看C語言的歷史,它的優點,并在第一章里面找到最經典的Hello World的源代碼,在你的IDE里敲出并運行你寫的第一個程序。
接著在開始正式地學習語言,但請先牢記所有人的切身體會:學語言,一定要動手寫。學過英語的人都知道,一個單詞能念出來,不一定能寫出來——相信是beleive還是believe,收到是receive還recieve?如果沒有多寫,你可能永遠分不清。學語言也是一樣:定義一個結構體(struct)的時候,最后一行是否要加上分號?在struct的大括號外面是否要加括號?typedef定義是怎么搞定的?for語句里面i要從0開始還是從1開始,中間的哪個引號是可以省略的?——這些都是初學者容易搞混掉的東西,只有實際動手去泡電腦,發現了自己的錯誤,才能夠真正記住。在這里沒有列出答案,是因為這些問題的答案需要你自己去發掘。——只把書翻爛的是傻子,能把鍵盤磨爛的才是大牛。
實際動手寫,OK,寫什么?有很多可以寫的。最直接的,教材上的每一個例題:當你看懂了以后,脫離教材,自己把它寫一遍。這樣的練習是非常必要的,它能夠為你打下良好的語言基礎——你一定不想在檢查完幾百行代碼以后發現錯誤只是因為數組的邊界問題沒搞清楚,甚至你自己根本無法發現你的錯誤。所以不要吝惜你的鍵盤(很便宜的,俺們都用Dell8115)。在學習C語言的過程中,最難搞定的應該就是要打通任督二脈:數組和指針。這也是C/C++功夫的精髓所在。C/C++之所以NB,是因為指針,靈活、高效;之所以被詬病,也是因為指針(程序員很容易濫用指針導致內存泄露、訪問錯誤等,電腦MM也有隱私的,別亂看)。所以在這里不妨慢慢地學,多想,多寫,心急吃不成熱豆腐,生米煮成熟飯也是需要時間的嘛。鏈表多寫幾次;寫一組用來處理矩陣的函數(或封裝為一個對象)。如果時間寬裕,最好還能做些課后的習題。此外,去泡各大OJ(Online Judge,在線評測系統,比如http://acm.whu.edu.cn/woj武漢大學在線評測系統)的服務器也是很贊的,因為OJ上的簡單題目也是非常好的練手方案,這里有WOJ的大部分簡單題列表http://acm.whu.edu.cn/blog/tag.php?tag=%25E5%2585%25A5%25E9%2597%25A8。做OJ的好處是,如果你的代碼中有不嚴謹的地方,很容易被OJ上高強度的測試數據檢查出來。
初學程序時,書上的例子很容易會有地方看不懂,是很正常的,這也正是轉變你思維方式的開始:試著用電腦的方式來"讀"程序。就是把你腦子訓練成CPU,一步一步地"執行"程序,有需要的話可以用紙張當作內存,"存儲"程序運行中的變量的值。這樣你就會很快地搞清楚電腦MM心里是咋想的,泡起來也就容易多了。這對于訓練自己的思維方式是非常重要的。有許多人在學習C語言一兩年以后仍然覺得把自己的想法轉化為程序代碼非常困難,即使是對著清晰地描述出來的具體實現步驟——不是因為他們不懂語法(他們可能有接近滿分的C語言考試成績),而是他們根本沒學會電腦MM的"思維"方式。當你學會了這種思維方式以后,你就能很快地把你的想法轉化為程序代碼了。
在寫代碼的過程中需要注意一個問題:代碼風格。首先對比一下下面兩段代碼:
int main(){char a[100];
for(int i=0;i<10;++i)
{
scanf("%s",a);
?? ??? printf("Hello %s!\n",a);
}
return 0; }
int main(){
char name[100];
for(int i = 0; i < 10; ++i){
?? ??? scanf("%s", name);
?? ??? printf("Hello %s!\n", name);
}
return 0;
}
喜歡哪一段代碼?你一定不會昧著良心說喜歡第一段吧:話都說不清楚還好意思去泡MM?雖然第一段代碼是故意那樣寫的,但是并沒有絲毫夸張。因為在初學者的代碼里經常會見到這樣的"風格"。初學者往往對此不以為然,他們的理由通常是:這段代碼很短,沒什么關系;以后再改,沒關系;看起來沒啥區別阿。上面那段代碼確實很短,即使像第一段那樣也容易讀懂,但是你不可能永遠只寫四五行的程序的。當程序變長以后,問題就來了:哎呀,編譯錯誤了!咋回事捏?噢,這里漏掉一個小括號,那里漏掉一個大括號。哎呀,運行結果不對了!咋回事捏?找了半天沒找到,發給大牛,被BS了:就這代碼,好意思讓大牛幫忙看阿,想泡MM也要有點自知之明阿!(過了些日子回頭無意中看到自己的代碼)這代碼TM誰寫的阿,這么惡心咋看阿?——所以,從敲出的第一行代碼開始培養自己的代碼風格,利己,利人。代碼風格里面主要需要注意的幾點是:1. 縮進,所有同一層次的語句縮進相同;2. 空格和空行的合理使用,使得代碼清晰易讀;3. 適當的注釋,讓代碼的閱讀更加簡單;4. 括號的使用;5. 變量命名應該規范,含義清晰。具體的內容,baidu和google會告訴你。請一定記得這句老話:磨刀不誤砍柴工!
終于,代碼寫好了,編譯也OK了,雙擊它,運行了!崩!地址0x00000000訪問錯誤,該內存不能為read(這位小哥注意點,MM在里面換衣服呢)。當然,錯誤可能還有很多種,最常見的是輸入對的,輸出不對(又是廢話)。舉例來說,目的是求一個一元二次方程的兩個實根,思路是清晰di,算法是明確di,程序是整潔di,就TM答案是錯誤di。咋回事?調阿!——不是程序調戲你,是你要去調戲程序,哦不,是調試程序。泡電腦MM的大牛們說,不會調試的程序員永遠寫不出好程序,真正的好程序是調出來。調試,是調試,嗯。是個人都知道程序有問題了,那問題到底再哪里呢?這就是調試的工作了。說白了就是找茬嘛。可以在程序中手工插入一些語句來實現暫停以及輸出中間變量的值來判斷程序在某一步是否出現了問題,以便定位錯誤;也可以依靠IDE或者其他調試工具(如gdb)提供的調試功能,在不修改源代碼的前提下按你的意思在一個可控制的環境中運行一個程序(例如,你可以一次運行程序的一行代碼,檢查變量的值,改變這些值,或者讓程序運行到某個定點然后停止等)。總而言之就是定位錯誤,為解決問題提供分析所需的重要線索。至于定位了問題以后,就不能再把人腦當電腦了,要好好想想為什么會出現這樣的問題。實在想不出來,就去請教能把電腦泡得服服貼貼的大牛吧。慢慢地積攢經驗,你也可以搞定她。
此外:雖然建議從C語言開始,但是最好能在開始寫代碼以后能盡早接觸面向對象的相關知識,這對之后的編碼是很有幫助的。
有人說,連C++的語言之父都要別人告訴他C++的用法,所以語言的學習是不會有止境的。在打好的堅實的語言基礎之后,可以看一些更深的書籍,推薦幾本好書,可以挑著看:《The C Programming Language》《The C++ Programming Language》《C++ Primer》《The C++ Standard Library》 《C++入門經典》。其中The C++ Standard Library主要講到了STL,很值得一看(STL這么有用的東西不學,會遭天遣的...)。
--
有很多人有這樣的疑問:現在我已經可以把電腦MM泡到腳軟,讓她幫我,額,解一元二次方程組或者統計一個文件里面單詞的數量,但是如果遇到更復雜的,比如說走迷宮,找出兩個字符串最長的公共子串這樣的問題——完蛋,我MM在迷宮里面迷路了,又沒有食物,咋辦?啥,烤字符串?毛,你個棒槌,人家mm要電動的。所以還是學習算法,把MM救出來現實一點。在學習了語言的基礎上,這里可以狹隘一點地看待算法這個概念:一種有效的組織計算機程序和數據并對數據處理以求解決遇到問題的辦法。組織計算機語言已經會了,但是還得把數據組織好阿。給一個簡單的問題,對100個數據排序,要怎么組織?定義100個變量? int a001, a002, ......, a100?你當然不會這么笨:學過數組的嘛!對,但是就像上面提到的走迷宮,這算法需要怎么組織其中用到的數據?迷宮本身可以用二維數組來保存,但是走迷宮時走過的步子以及遇到的岔道這些,要怎么組織起來?這里需要用到棧或者隊列這些更高級的道具——這就屬于 數據結構,Data Structure 的范疇了。
百度百科 -> 數據結構 說:俺是計算機存儲、組織數據的方式。俺是指相互之間存在一種或多種特定關系的數據元素的集合。通常情況下,精心選擇的俺可以帶來更高的運行或者存儲效率的算法。俺往往同高效的檢索算法和索引技術有關。俺在計算機科學界至今沒有標準的定義。
Orz...看起來真累吧,咱是要來泡MM的,不是來聽天書的。簡單點說,那就是要搞清楚怎么樣在計算機中組織數據(存儲,讀取,處理……)的一門學問。這和算法是相輔相成,密不可分的。某種數據結構的構建本身就需要算法的支持;一個好的算法如果沒有合適的數據結構支撐,就像大力水手吃白菜,也就能頂個P用。
學習數據結構,當然也需要一本好書(原因就不說了吧,省得有人說俺財迷),這里推薦清華大學嚴蔚敏老師的《數據結構》,或者《數據結構 C++ 語言描述》。不論哪本,你都會學到最大眾化的數據結構,諸如順序表、棧、隊列、串、樹、圖等內容。至于具體怎么學——看書去(p.s.建議學習圖的時候跟進學習離散數學里面的圖論)。想要學好算法,這些數據結構必然是要熟練掌握的,而想要熟練掌握這些數據結構——自古華山一條路,寫。在理解了某個數據結構的實現方法以后,自己寫代碼實現它,才能夠真正掌握它。你看電視劇里大俠在變NB之前沒有那個是只看小人書;都是要天天苦練的。
要說明的是,這里學的都是數據結構的基礎,不能滿足所有算法的需求,常常需要對它們進行改造,比如說順序表和樹的私生子——線段樹~充分證明了雜種優勢理論的正確性。再比如后綴數組,再比如十字鏈表,再比如。。。(俺肚子里沒存貨了,大牛來補充點)。。。 這些特殊的數據結構在平常的學習中很少會接觸到,這就需要多做acm/icpc的題目,不斷積累。
另外,建議在實現某個數據結構的時候,用面向對象的思想來完成,寫一個class,而不是用一堆聯系松散的函數。(武大用的那本教程真ooxx)
--
當你終于能指使電腦mm去排隊、種樹、畫圖以后,就可以開始好好修煉算法了。
百度百科-> 算法 說:俺英文名是Algorithm,就是一系列解決問題的清晰指令,也就是說,能夠對一定規范的輸入,在有限時間內獲得所要求的輸出。
Orz...那最后幾個字說得輕松阿,也不想想《算法導論》這塊磚頭有多厚。額滴神哪,Knuth還有幾本《The Art of Computer Programming》好像好還沒寫完。。。先看這些東西吧。。。同樣的,這里面不能學到所有的算法,還是需要多做題,積累。
--
最后,提一些icpc相關的東西
1. OJ, Online Judge
在線評測系統,知名的有vijos, usaco,poj, zoj等。提供一系列題目,允許瀏覽者提交相應的源代碼并對其進行測試,是否能夠完全符合題目要求。
以武漢大學在線評測系統woj為例,在http://acm.whu.edu.cn/woj注冊并登錄以后可以試著打開
http://acm.whu.edu.cn/oak/problem/problem.jsp?problem_id=1001
這是最簡單的題目,輸入a, b,要求輸出a與b的和(大多數OJ都有這一題,供測試使用)
(詳細看看這個頁面Hint部分的內容,有不了解的地方,閱讀FAQ:http://acm.whu.edu.cn/oak/faq.html)
點擊頁面底部的submit按鈕,會轉到有個大文本框的網頁,把你的代碼粘貼到文本框中,點擊下面的submit按鈕
然后瀏覽器就會把你的代碼提交給服務器進行測試,并自動轉到結果頁面查看。
如果對應的結果是Accepted(簡稱AC),說明這道題你做對了,其他情況參見FAQ里的說明。
~一些OJ的鏈接
http://acm.timus.ru/(外國)
http://acm.hdu.edu.cn/杭州電子科技大學
http://acm.pku.edu.cn/JudgeOnline/北京大學
http://acm.nenu.edu.cn/或者http://acm.hrbeu.edu.cn/哈工程
http://acm.jlu.edu.cn/joj吉林大學
http://acm.tju.edu.cn/天津大學
??http://acm.whu.edu.cn/武漢大學
http://acm.sgu.ru/俄羅斯圣薩拉托夫州大學在線題庫
http://acm.mipt.ru/judge/bin/problems.pl?lang=en俄羅斯莫斯科物理技術學院
https://spoj.sphere.pl/波蘭格但斯克理工大學
http://acm.uva.es/西班牙的Universidad de Valladolid在線題
2. 參見我之前寫的這篇日志http://www.felix021.com/blog/read.php?1318
?? 轉自武漢大學felix大牛blog
總結
以上是生活随笔為你收集整理的[Acm] 开始你的ACM-ICPC之旅(转)的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: OpenSolaris北京用户组的第一次
- 下一篇: 最近比较毁硬件