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