ACM入門之新手入門

zyearn發表於2012-07-20

第一章 新手入門

1.ACM國際大學生程式設計競賽簡介

1)背景與歷史

1970年在美國TexasA&M大學舉辦了首次區域競賽,從而拉開了國際大學生程式設計競賽的序幕。1977年,該項競賽被分為兩個級別:區域賽和總決賽,這便是現代ACM競賽的開始。在亞洲、美國、歐洲、太平洋地區均設有區域賽點。1995至1996年,來自世界各地的一千多支s代表隊參加了ACM區域競賽。ACM大學生程式設計競賽由美國計算機協會(ACM)舉辦,旨在向全世界的大學生提供一個展示和鍛鍊其解決問題和運用計算機能力的機會,現已成為全世界範圍內歷史最悠久、規模最大的大學生程式設計競賽。

2)競賽組織

競賽在由各高等院校派出的3人一組的隊伍間進行,分兩個級別。參賽隊應首先參加每年9月至11月在世界各地舉行的“區域競賽(Regional Contest)”。各區域競賽得分最高的隊伍自動進入第二年3月在美國舉行的“總決賽(Final Contest)”,其它的高分隊伍也有可能被邀請參加決賽。每個學校有一名教師主管隊伍,稱為“領隊”(faculty advisor),他負責選手的資格認定並指定或自己擔任該隊的教練(coach)。每支隊伍最多由三名選手(contestant)組成,每個選手必須是正在主管學校攻讀學位的學生。每支隊伍最多允許有一名選手具有學士學位,已經參加兩次決賽的選手不得再參加區域競賽。

3)競賽形式與評分辦法

競賽進行5個小時,一般有6~8道試題,由同隊的三名選手使用同一臺計算機協作完成。當解決了一道試題之後,將其提交給評委,由評委判斷其是否正確。若提交的程式執行不正確,則該程式將被退回給參賽隊,參賽隊可以進行修改後再一次提交該問題。

程式執行不正確是指出現以下4種情況之一:

(1)執行出錯(run-time error);

(2)執行超時〔time-limit exceeded〕;

(3)執行結果錯誤(wrong answer);

(4)執行結果輸出格式錯誤(presentation error)。

競賽結束後,參賽各隊以解出問題的多少進行排名,若解出問題數相同,按照總用時的長短排名。總用時為每個解決了的問題所用時間之和。一個解決了的問題所用的時間是競賽開始到提交被接受的時間加上該問題的罰時(每次提交通不過,罰時20分鐘)。沒有解決的問題不記時。美國英語為競賽的工作語言。競賽的所有書面材料(包括試題)將用美國英語寫出,區域競賽中可以使用其它語言。總決賽可以使用的程式設計語言包括PASCAL,C,C++及Java,也可以使用其它語言。具體的作業系統及語言版本各年有所不同。

4)競賽獎勵情況

總決賽前十名的隊伍將得到高額獎學金:第一名獎金為12000美元,第二名獎金為

6000美元,第三名獎金為3000美元,第四名至第十名將各得到l500美元。除此之外還將

承認北美冠軍、歐洲冠軍、南太平洋冠軍及亞洲冠軍。

2.ACM競賽需要的知識

語言是最重要的基本功

無論側重於什麼方面,只要是通過計算機程式去最終實現的競賽,語言都是大家要過的第一道關。亞洲賽區的比賽支援的語言包括C/C++與JAVA。首先說說JAVA,眾所周知,作為物件導向的王牌語言,JAVA在大型工程的組織與安全性方面有著自己獨特的優勢,但是對於資訊學比賽的具體場合,JAVA則顯得不那麼合適,它對於輸入輸出流的操作相比於C++要繁雜很多,更為重要的是JAVA程式的執行速度要比C++慢10倍以上,而競賽中對於JAVA程式的執行時限卻往往得不到同等比例的放寬,這無疑對演算法設計提出了更高的要求,是相當不利的。其實,並不主張大家在這種場合過多地運用物件導向的程式設計思維,因為對於小程式來說這不旦需要花費更多的時間去編寫程式碼,也會降低程式的執行效率。

接著說C和C++。在賽場上使用純C的選手還是大有人在的,它們主要是看重了純C在效率上的優勢,所以這部分同學如果時間有限,並不需要急著去學習新的語言,只要提高了自己在演算法設計上的造詣,純C一樣能發揮巨大的威力。

而C++相對於C,在輸入輸出流上的封裝大大方便了我們的操作,同時降低了出錯的可能性,並且能夠很好地實現標準流與檔案流的切換,方便了除錯的工作。如果有些同學比較在意這點,可以嘗試C和C++的混編,畢竟僅僅學習C++的流操作還是不花什麼時間的。

C++的另一個支援來源於標準模版庫(STL),庫中提供的對於基本資料結構的統一介面操作和基本演算法的實現可以縮減我們編寫程式碼的長度,這可以節省一些時間。但是,與此相對的,使用STL要在效率上做出一些犧牲,對於輸入規模很大的題目,有時候必須放棄STL,這意味著我們不能存在“有了STL就可以不去管基本演算法的實現”的想法;另外,熟練和恰當地使用STL必須經過一定時間的積累,準確地瞭解各種操作的時間複雜度,切忌對STL中不熟悉的部分濫用,因為這其中蘊涵著許多初學者不易發現的陷阱。

通過以上的分析,我們可以看出僅就資訊學競賽而言,對語言的掌握並不要求十分全面,但是對於經常用到的部分,必須十分熟練,不允許有半點不清楚的地方.

以數學為主的基礎知識十分重要

雖然被定性為程式設計競賽,但是參賽選手所遇到的問題更多的是沒有解決問題的思路,而不是有了思路卻死活不能實現,這就是平時積累的基礎知識不夠。今年World Final的總冠軍是波蘭華沙大學,其成員出自於數學系而非計算機系,這就是一個鮮活的例子。競賽中對於基礎學科的涉及主要集中於數學,此外對於物理、電路等等也可能有一定應用,但是不多。因此,大一的同學也不必為自己還沒學資料結構而感到不知從何入手提高,把數學撿起來吧!下面我來談談在競賽中應用的數學的主要分支。

離散數學

離散數學作為計算機學科的基礎是競賽中涉及最多的數學分支,重中之重又在於圖論和組合數學,尤其是圖論。圖論之所以運用最多是因為它的變化最多,而且可以輕易地結合基本資料結構和許多演算法的基本思想,較多用到的知識包括連通性判斷、DFS和BFS,關節點和關鍵路徑、尤拉回路、最小生成樹、最短路徑、二部圖匹配和網路流等等。雖然這部分的比重很大,但是往往也是競賽中的難題所在,如果有初學者對於這部分的某些具體內容暫時感到力不從心,也不必著急,可以慢慢積累。

組合數學

競賽中設計的組合計數問題大都需要用組合數學來解決,組合數學中的知識相比於圖論要簡單一些,很多知識對於小學上過奧校的同學來說已經十分熟悉,但是也有一些部分需要先對代數結構中的群論有初步瞭解才能進行學習。組合數學在競賽中很少以難題的形式出現,但是如果積累不夠,任何一道這方面的題目卻都有可能成為難題。

數論

以素數判斷和同餘為模型構造出來的題目往往需要較多的數論知識來解決,這部分在競賽中的比重並不大,但只要來上一道,也足以使知識不足的人冥思苦想上一陣時間。素數判斷和同餘最常見的是在以密碼學為背景的題目中出現,在運用密碼學常識確定大概的過程之後,核心演算法往往要涉及數論的內容。

計算幾何

計算幾何相比於其它部分來說是比較獨立的,就是說它和其它的知識點很少有過多的結合,較常用到的部分包括—線段相交的判斷、多邊形面積的計算、內點外點的判斷、凸包等等。計算幾何的題目難度不會很大,但也永遠不會成為最弱的題。

線性代數

對線性代數的應用都是圍繞矩陣展開的,一些表面上是模擬的題目往往可以藉助於矩陣來找到更好的演算法。

計算機專業知識

雖然數學十分十分重要,但是如果讓三個只會數學的人蔘加比賽,我相信多數情況下會比三個只會資料結構與演算法的人得到更為悲慘的結局。

資料結構

掌握佇列、堆疊和圖的基本表達與操作是必需的,至於樹,我個人覺得需要建樹的問題有但是並不多。(但是樹往往是很重要的分析工具)除此之外,排序和查詢並不需要對所有方式都能很熟練的掌握,但你必須保證自己對於各種情況都有一個在時間複雜度上滿足最低要求的解決方案。說到時間複雜度,就又該說說雜湊表了,競賽時對時間的限制遠遠多於對空間的限制,這要求大家儘快掌握“以空間換時間”的原則策略,能用雜湊表來儲存的資料一定不要到時候再去查詢,如果實在不能建雜湊表,再看看能否建二叉查詢樹等等—這都是爭取時間的策略,掌握這些技巧需要大家對資料結構尤其是演算法複雜度有比較全面的理性和感性認識。

演算法

演算法中最基本和常用的是搜尋,主要是回溯和分支限界法的使用。這裡要說的是,有些初學者在學習這些搜尋基本演算法是不太注意剪枝,這是十分不可取的,因為所有搜尋的題目給你的測試用例都不會有很大的規模,你往往察覺不出程式執行的時間問題,但是真正的測試資料一定能過濾出那些沒有剪枝的演算法。實際上參賽選手基本上都會使用常用的搜尋演算法,題目的區分度往往就是建立在諸如剪枝之類的優化上了。

常用演算法中的另一類是以“相似或相同子問題”為核心的,包括遞推、遞迴、貪心法和動態規劃。這其中比較難於掌握的就是動態規劃(DP),如何抽象出重複的子問題是很多題目的難點所在,筆者建議初學者仔細理解圖論中一些以動態規劃為基本思想所建立起來的基本演算法(比如Floyd-Warshall演算法),並且多閱讀一些定理的證明,這雖然不能有什麼直接的幫助,但是長期堅持就會對思維很有幫助。

3.      對新手的一些建議

首先要看一些基礎的演算法書籍,把基本的演算法搞懂。像遞迴、二分、寬搜、深搜、簡單的圖論、數論、簡單的組合數學。重點根據書上的例題理解演算法的實質、思想,能做到有一定領悟。這時需要做一些題目來鞏固了。

先可以做搜尋題,搜尋是博大精深的,諸多細節技巧都需要靠平時的積累領悟,根據自己練習的目的挑一些題練習。然後可以做簡單的數學題,對組合數學、數論有個大致的概念。

再然後可以做DP類題目了。DP也是非一日之功,練好DP就像練好了內功,這時可以做一些DP的基礎題,體會一下,然後做一些提高題,如果不會做,一定要自己想通為什麼別人這樣設定狀態陣列,他的技巧在哪裡。oibh上很多的國家集訓隊關於DP的論文是必看的。

圖論裡有很多基礎的東西需要學習,先把圖論裡面基本的定義看懂,然後把經典的演算法看懂,比如最短路、生成樹、割點、連通分量等等。如果不會做,一定要好好看書。

很多新手會問碰到不會做的題目怎麼辦。首先應該考察一下為什麼不會做這題,如果是書本上的知識點沒掌握,那要趕緊把書本找來,仔細理解之後再來想這題。如果知識點基本都掌握了,那麼可以利用網路的資源,多搜尋一下關於這題的討論,看看別人是怎麼想的,看是否可以給自己提供思路。總之一條,要自己多開動腦子。重在理解這一題的演算法,而不是隻知道演算法,自己把它程式設計實現了就算了。對待演算法和程式要用嚴謹的態度,沒有搞懂的地方要花力氣把它搞懂,這樣才能不斷提高。

看書是必須的,而且也是迅速提高的最好方法,不要等到做題時才去理解書上的知識點,而要對知識點有了充分的理解後再去做題,這樣才能事半功倍,否則看到難題,從哪方面下手的思路都沒有。

高階的貪心,300行的寬搜,A*,STL,諸多的剪枝技巧,統計,查詢,treap,對DP狀態的優化,帶集合的DP,平面圖,計算幾何,數論......要學的東西很多。但我相信只要努力你們肯定會取得不錯的成績。和別人比賽,其實是和自己比賽,考場上完全是實力的體現,會就是會,不會就是做不出來。訓練時間每個人情況不一樣,長短不一,但重在看個人悟性,水平達到一定程度之後會發現有質的變化,理解演算法簡直是小菜。

這裡強調的還是個思維能力的問題,不是為了做題而做題,做題其實是為了訓練自己的思維能力和程式設計能力,從訓練中能得到的最大的收穫就是提升了思維,套用比較流行的一個詞就是“腦力”。這也是為什麼說進省隊是個標誌,進了省隊說明你前期有了一定的積累,和那裡的一些高手一接觸自然自己的思路就大大開闊了,對於演算法會有一個更深層次的理解。就算只參加了省隊的選拔賽,對自己的幫助也是很大的。用一牛人的話說,沒進過省隊就等於沒見過世面。

那大家一定達不到那些現今強人的水平嗎?當然不是。強人不是天生就強的,也是從菜鳥做起的,成功地原因只有一個-——勤奮。他們的思維能力或者腦力不是天生就這樣的。但隨便提現今的一個牛人,題量都是上千。他們默默地積累和嚴謹的態度才取得了現在的成績。有人說上千題,太恐怖了啊,我做一個題都得花幾小時,有些想幾天還做不出。一開始自然是這樣,知識點眾多,考查範圍廣大,對這些現成的知識要慢慢消化,每個知識點都掌握後,做只考這些知識點的題自然就快了。積累到一定程度後就會發現做題的樂趣,以前很崇拜那些說“今天上課太累了,做幾道題休息一下”的人,不知不覺,做題對我來說也成了最大的樂趣。有些題只考查單一的知識點,有些題把幾個知識點結合起來考查。比如先用平面圖裡面的幾個知識點,然後凸包求一下,然後DP一下,或者線性方程組解一下再搞個匹配等等,這些題看上去很複雜,但若這些知識點都不折不扣地掌握的話,做這些題自然就像切菜了。題目也是人出的,如果只看現成的這些知識點的話,出題者的思維也是有限的。

參加這個比賽對程式設計能力的提高也是大有好處的,十分鐘上百行無錯程式碼,快速實現邏輯較複雜的演算法,debug技巧......而且對語言的理解也能上好幾個臺階。我們還沒有迎來下一次的程式設計技術革命,程式設計仍舊是有侷限的,它強迫我們像計算機一樣思考,而不是令計算機像我們的大腦一樣思考,這是我們需要花巨大的努力去克服的。很多人對我說的這句話可能不太理解,至少感受不深。如果Debug的時間超過寫程式時間的1/2,那就是失敗的。一切都要慢慢訓練,持之以恆之後,擁有良好的程式設計習慣和風格應該是每個人所追求的。程式設計的境界永無止境!

以前人們常說看書可以升級大腦,對於計算機及其相關專業的同學來說,參加acm比賽是最好的升級大腦的方法,思維能力的提升可以讓我們受益無窮,而程式設計的能力和技巧則會因為編寫大量的程式碼而大幅提高。或許今後再也沒有這樣一個機會能讓你計算機水平飛速增長。對演算法和資料結構理解深入後研究計算機專業的其他課程有如“會當凌絕頂,一覽眾山小”。所以低年級的同學全身心的投入進來是絕對有好處的。有一年多的積累就能小有成績了。只要堅持下來,踏踏實實,努力提升自身水平,一定可以實現自己的目標!

做acm看似是枯燥的,但一旦入了門,就會發現其中有無窮的樂趣,即使訓練了不參加比賽,對自己也是一個很好的提高。

知識的積累固然重要,但是資訊學終究不是看出來的,而是練出來的,這是多少前人最深的一點體會,只有通過具體題目的分析和實踐,才能真正掌握數學的使用和演算法的應用,並在不斷的練習中增加程式設計經驗和技巧,提高對時間複雜度的感性認識,優化時間的分配,加強團隊的配合。總之,在這裡光有紙上談兵是絕對不行的,必須要通過實戰來鍛鍊自己。

練習站點推薦:

(1)[acm.pku.edu.cn/JudegOnline] POJ收集了大量比賽真題,其中不乏簡單題;POJ的伺服器效能良好,響應速度快;POJ經常舉辦網上練習賽,練習賽是增長比賽經驗的最好途徑。

(2)[acm.zju.edu.cn] ZOJ是國內最早出現的OJ,有一定的權威性。ZOJ的論壇是最好的資源,提供了“題目分類”,可以進行專題練習。

(3)[acm.sgu.ru] SGU是俄羅斯的。比較注重演算法和數學。OI的頂尖高手都在這裡做題。

學習資料推薦:

演算法導論(英文版)Introduction to Alogrithms.

演算法藝術與資訊學競賽 劉汝佳 黃亮 著

歷年資訊學奧賽中國國家隊論文

ACM國際大學生程式設計競賽試題與解析

組合數學的演算法與程式設計

圖論的演算法與程式設計

實用演算法的分析與程式設計

計算幾何基礎知識




相關文章