計算機考研機試攻略 - 高分篇


目錄

第一章 從零開始

1.1機試分析

1.2 IDE的選擇與評測結果

1.3 DreamJudge的使用

1.4輸入輸出技巧

1.5頭文件技巧

1.6數組使用技巧

1.7審時度勢 — 複雜度與是否可做

1.8 C++ STL的使用

1.9多組輸入的問題

第二章 入門經典

2.1 簡單模擬

2.2 進制轉換類問題

2.3 排版類問題

2.4 日期類問題

2.5 字符串類問題

2.6 排序類問題

2.7 查找類問題

2.8 貪心類問題

2.9 鏈表類問題

第三章 數學

3.1 同模餘定理

3.2 最大公約數(GCD)

3.3 最小公倍數(LCM)

3.4 斐波那契數列

3.5 素數判定

3.6 素數篩選

3.7 分解素因數

3.8 二分快速冪

3.9 常見數學公式總結

3.10 規律神器OEIS

第四章 高精度問題

4.1 Python解法

4.2 Java解法

4.3 C/C++解法

第五章 數據結構

5.1 棧的應用

5.2 哈夫曼樹

5.3 二叉樹

5.4 二叉排序樹

5.5 hash算法

5.6 前綴樹

第六章 搜索

6.1 暴力枚舉

6.2 廣度優先搜索(BFS)

6.3 遞歸及其應用

6.4 深度優先搜索(DFS)

6.5 搜索剪枝技巧

6.6終極偏分技巧

第七章 圖論

7.1 理論基礎

7.2 圖的存儲

7.3 並查集

7.4 最小生成樹問題

7.5 最短路徑問題

7.6 拓撲排序

7.7 打印路徑類問題

第八章 動態規劃

8.1 遞推求解

8.2最大子段和

8.3 最長上升子序列(LIS)

8.4 最長公共子序列(LCS)

8.5 揹包類問題

8.6 記憶化搜索

8.7 字符串相關的動態規劃

 


 

 

第一章 從零開始

 

1.1機試分析

首先我們來看一下機試是怎樣的一種考覈模式

全國所有院校的機試都大同小異,大部分有自己OJ(Online Judge也就是在線代碼測評平臺)的學校都會採用OJ上做題的方式來進行考覈。這種考覈方式的好處是公開透明,機器進行判題並給分,就像N諾的DreamJudge一樣。沒有OJ的學校只能人工進行判題,人工判題的話,一方面是主觀性比較強,可能還會對其他方面進行考量,這個就需要自己去了解了。總的來說,不論是OJ判題還是人工判題,代碼都要能通過測試用例才能得到分數。

 

針對機試我們應該怎麼去訓練提升自己呢

首先,一定要做題,在N諾上做題,不要自己埋頭看書,在不斷做題的過程中才能提升自己。如果非要用一個量化的標準來衡量的話,至少要在N諾上做夠100題(也就是達到磚石II以上段位),才能保證你機試達到自己滿意的成績。題量是很關鍵的,看懂的題再多,都不如自己實際敲代碼去解決問題更穩妥。

 

解題速度也是很重要的

其實解題速度和題量是正相關的,相信題量足夠的同學,解題的速度都不會太慢。機試一般2-3個小時左右,要解決5-8道題。平均下來一道題最多半個小時,從讀題、分析題意、思考解法、敲代碼、調試、測試數據到最後提交這整個流程下來,如果你平時訓練的少,讀題慢、理解題意慢、思考解法慢、敲代碼慢、調試慢,這樣一算下來,一道簡單的題都可能要一個小時才能寫出來,說不定題目還有坑點,再慢慢調試,基本上就涼了。

 

 

 

多打比賽也是很重要的

很多同學平時做的題很多,解題速度也挺快,但是一到比賽或者考試的時候就會卡題,在壓力的情況下發揮失常比比皆是,所以平時就要鍛鍊自己的抗壓能力。

N諾上除了每個周定期舉辦的小白賽,還特別爲大家準備了考研機試衝刺八套卷

在本書的最後,你可以看到關於考研機試衝刺八套卷的詳細信息。通過這八套卷的練習,相信會讓你的水平產生一個脫胎換骨的變化。

 

 

準備好模板是至關重要的

一般來說,機試都可以帶書和紙質資料進入考場。所以提前把那些函數的用法和算法的模板準備好是很重要的,一方面是增加自己的信心,萬一沒記住還可以翻開來看一下。另外說不定考到原題或者類似的題,就可以直接秒殺了。

 

 

特別提醒:本書默認讀者是會C語言的基本語法的,比如if語句、for語句等等。

 

 

 

C語言基本語法還未掌握的同學建議學習N諾的C語言快速入門課程(3天學會C語言不是夢)

 

地址:http://www.noobdream.com/Major/majorinfo/1/

 

 

 

 

 

 

1.2 IDE的選擇與評測結果

建議選擇CodeBlocks作爲平時敲代碼練習的IDE

下載地址:http://www.noobdream.com/Major/article/1/

 

常見做題結果反饋

Accepted:答案正確,恭喜你正確通過了這道題目。

Wrong Answer: 答案錯誤,出現這個錯誤的原因一般是你的程序實現或思路出現了問題,或者數據範圍邊界沒有考慮到。

Runtime Error:運行時錯誤,出現這個錯誤的原因一般是數組越界或者遞歸過深導致棧溢出。

Presentation Error:輸出格式錯誤 ,出現這個錯誤的原因一般是末尾多了或少了空格,多了或少了換行

Time Limit Exceeded:程序運行超時,出現這個錯誤的原因一般是你的算法不夠優秀,導致程序運行時間過長。

Memory Limit Exceeded:運行內存超限,出現這個錯誤的原因一般是你的程序申請太大了空間,超過了題目規定的空間大小。

Compile Error:編譯錯誤,這個不用說了吧,就是你的代碼存在語法錯誤,檢查一下是不是選擇錯誤的語言提交了。

Output Limit Exceeded:輸出超限,程序輸出過多的內容,一般是循環出了問題導致多次輸出或者是調試信息忘記刪除了。

Submitting:提交中,請等待題目結果的返回,由於判題機有性能差異,所以返回結果的速度也不一樣,N諾上做題一般瞬間就能出結果。

 

以上幾種結果就是評判系統可能會返回的幾種常見結果。若返回Accept,那麼你就可以拿到該題所有分數,如果返回其他結果,則要看你報考學校的考試規則,是根據通過測試點的百分比給分還是隻要不是AC就得0分。

 

 

1.3 DreamJudge的使用

DreamJudge是一個在線代碼測評的平臺,可以很方便的檢驗自身的學習情使用DreamJudge的方法很簡單,通過百度搜索N諾或者在瀏覽器中輸入網址www.noobdream.com進入N諾然後點擊網站導航上方的DreamJudge就可以進去啦。

 

做題頁面如下:

 

首先要登錄我們的N諾賬號,然後開始做題。如果沒有賬號,右上角點擊註冊,然後註冊一個賬號就可以了。

然後將代碼粘貼到右邊的輸入框裏,在上面選擇使用哪種語言提交,C/C++/Java/Python,建議選擇C++提交,因爲C++可以編譯C語言代碼。我們一般寫代碼爲了方便,都會使用一點C++的特性來幫助我們快速解決一道題目。如果代碼裏含有C++的特性卻選擇了C語言提交的話,會返回編譯錯誤的提示信息。

 

1.4輸入輸出技巧

輸入int型變量 scanf("%d", &x);

輸入double型變量 scanf("%lf", &x); 不用float直接double

輸入char類型變量 scanf("%c", &x);

輸入字符串數組 scanf("%s", s);

輸出與輸入表示方式一致

printf("%s\n", s);

 

scanf輸入解析

輸入日期 2019-10-21

  1. int year, month, day;  
  2. scanf("%d-%d-%d", &year, &month, &day);  
  3. printf("%d %d %d\n", year, month, day);  

這樣可以直接解析出來

 

輸入時間 18:21:30

  1. int hour, minute, second;  
  2. scanf("%d:%d:%d", &hour, &minute, &second);  
  3. printf("%d %d %d\n", hour, minute, second);  

 

scanf和gets

輸入一行字符串帶空格的話,使用gets,scanf遇到空格會自動結束

  1. char s[105];  
  2. gets(s);//例如輸入how are you?  
  3. printf("%s\n", s);  

 

getchar和putchar

讀入單個字符和輸出單個字符,一般在scanf和gets中間使用getchar用於消除回車’\n’的影響

 

 

 

輸出進制轉換

  1. int a = 10;  
  2. printf("%x\n", a);//小寫十六進制輸出 答案a  
  3. printf("%X\n", a);//大寫十六進制輸出 答案A  
  4. printf("%o\n", a);//八進制輸出  答案12  

 

輸出增加前置0

  1. int a = 5;  
  2. printf("%02d\n", a);//其中2代表寬度 不足的地方用0補充  
  3. 輸出結果05  
  4. printf("%04d\n", a);  
  5. 輸出結果0005  

 

輸出保留小數

  1. double a = 3.6;  
  2. printf("%.2lf\n", a);//2表示保留兩位小數  

輸出結果3.60

 

有小數輸出小數,沒小數輸出整數

%g

 

特別注意:中文符號和英文符號要對應一致,一般情況下都用英文符號(如中文逗號,和英文逗號,)

 

long long的使用

很多情況下的計算會超出int,比如求N!,N比較大的時候int就存不下了,這時候我們就要用long long。那麼我們怎麼去記int和long long的範圍呢,有一個簡單的記法,int範圍-1e9到1e9,long long範圍-1e18到1e18,這樣就容易記了。

  1. long long x;  
  2. scanf("%lld", &x);  
  3. printf("%lld\n", x);  

 

 

字符的ASCII碼

不要硬記,直接輸出來看

printf("%d\n", 'a');

輸出結果97

printf("%d\n", 'A');

輸出結果65

 

特別注意:如果遇到需要ASCII碼的題目的時候記住char字符和int值是可以相互轉化的。

 

cin 和 cout

很多時候使用C++的輸入輸出寫起來更簡單,在應對一些輸入輸出量不是很大的題目的時候,我們會採用cin和cout來提高我們的解題速度。

比如求兩個數的和:

  1. #include <iostream>//輸入輸出函數的頭文件  
  2.   
  3. int main() {  
  4.     int a, b;  
  5.     cin >> a >> b;  
  6.     cout << a + b;//輸出兩個數之和  
  7. }  

 

可以發現,C++的輸入輸出敲起來更快,這是我們會使用它來進行混合編程的原因之一。

另外,C++的string類對於字符串操作很方便,但是輸入輸出只能用cin、cout。

特別注意:大家一定平時練習的時候不要排斥混合編程,即C與C++語法混用,然後用C++提交。這樣可以極大的幫助你以更快的速度解決一道你用純C寫半天才能解決的題目,留下充裕的時間去解決更多的題目。

友情提示:當輸入或輸出格式有特殊要求的時候,cin和cout不方便解決,那麼我們還是使用scanf和printf來解決問題。要注意的是printf儘量不要和cout同時使用,會發生一些不可控的意外。

 

 

1.5頭文件技巧

 

這裏推薦一個萬能頭文件給大家

 

  1. #include <bits/stdc++.h>  
  2. using namespace std;  

 

不過要看考試的評測機支不支持,絕大部分都是支持的。當然,我們還可以留一手,準備一個完整的頭文件,在考試開始前敲上去就行。

 

  1. #include <stdio.h>  
  2. #include <string.h>  
  3. #include <math.h>  
  4. #include <stdlib.h>  
  5. #include <time.h>  
  6. #include <algorithm>  
  7. #include <iostream>  
  8. #include <queue>  
  9. #include <stack>  
  10. #include <vector>  
  11. #include <string>  
  12. using namespace std;  
  13.   
  14. int main() {  
  15.   
  16.     return 0;  
  17. }  

 

特別注意:頭文件可以多,但是不能少,但是有一些頭文件是不允許的,大部分OJ爲了系統安全性考慮限制了一些特殊的API,導致一些頭文件不能使用,比如windows.h。當然不同的OJ的安全策略也不盡相同,一般不涉及到系統函數的頭文件一般都是可以使用的。

 

 

1.6數組使用技巧

數組除了可以存儲數據以外,還可以用來進行標記。

 

例題:

輸入N(N<=100)個數,每個數的範圍> 0 並且 <= 100,請將每個不同的數從小到大輸出並且輸出它對應的個數。

樣例輸入

8

3 2 2 1 1 4 5 5

樣例輸出

1 2

2 2

3 1

4 1

5 2

 

代碼如下

  1. #include <bits/stdc++.h>  
  2. using namespace std;  
  3.   
  4. int f[105]={0};//注意,儘量將數組開在全局  
  5. int main() {  
  6.     int n,x;  
  7.     scanf("%d", &n);  
  8.     for (int i = 0; i < n; i++) {  
  9.         scanf("%d", &x);  
  10.         f[x]++;  
  11.     }  
  12.     for (int i = 0; i <= 100; i++) {  
  13.         if (f[i] > 0) printf("%d %d\n", i, f[i]);  
  14.     }  
  15.     return 0;  
  16. }  

在這個程序中,我們使用一個數組f記錄每個值得個數,f[i]的值表示i這個數有多少個,初始的時候每個值的個數都是0。

 

數組的使用不一定從0開始,可以從任意下標開始,只要我們使用的時候對應上就行。

 

例如我們存儲地圖的時候

####

#.##

##@#

####

 

假設一個地圖是這樣的,我們要用二維字符數組來存儲,我們可以像下面這樣做。

 

  1. #include <bits/stdc++.h>  
  2. using namespace std;  
  3.   
  4. char mpt[10][10];  
  5. int main() {  
  6.     for (int i = 1; i <= 4; i++) {  
  7.         scanf("%s", mpt[i] + 1);  
  8.         /* 不要用下面這種輸入方式,否則會出問題,因爲回車也算一個char字符 
  9.         for (int j = 1; j <= 4; j++) { 
  10.             scanf("%c", &mpt[i][j]); 
  11.         } 
  12.         */  
  13.     }  
  14.     for (int i = 1; i <= 4; i++) {  
  15.         for (int j = 1; j <= 4; j++) {  
  16.             printf("%c", mpt[i][j]);  
  17.         }  
  18.         printf("\n");  
  19.     }  
  20.     return 0;  
  21. }  

 

 

數組還可以嵌套使用

我們將上面那題改進一下

 

例題:

輸入N(N<=100)個數,每個數的範圍> 0 並且 <= 100,請將每個不同的數從小到大輸出並且輸出它對應的個數。如果多個值有相同的個數,輸出值最大的那個。

樣例輸入

8

3 2 2 1 1 4 5 5

樣例輸出

4 1

5 2

 

代碼如下

  1. #include <bits/stdc++.h>  
  2. using namespace std;  
  3.   
  4. int f[105] = {0};  
  5. int p[105] = {0};//p[i]表示有i個這樣的數的最大值是多少  
  6. int main() {  
  7.     int n,x;  
  8.     scanf("%d", &n);  
  9.     for (int i = 0; i < n; i++) {  
  10.         scanf("%d", &x);  
  11.         f[x]++;  
  12.     }  
  13.     for (int i = 0; i <= 100; i++) p[f[i]] = i;  
  14.     for (int i = 1; i <= 100; i++) {  
  15.         if (p[i] > 0) printf("%d %d\n", p[i], i);  
  16.     }  
  17.     return 0;  
  18. }  

 

 

1.7審時度勢 — 複雜度與是否可做

在做題之前,我們要先判斷這道題是否可做,對於簡單的模擬題,大家肯定都知道,我能寫出來就是可做,寫不出來就是不可做。但是對於循環嵌套和算法題,我們就需要去判斷思考自己設計的算法是否可以通過這道題。

不懂複雜度計算的同學去看一下數據結構課程的第一章,很簡單的。

 

例如:我們寫一個冒泡排序,它是兩個for循環,時間複雜度是O(N^2)

那麼在1S內我們最多可以對多少個數進行冒泡排序呢,N在1000 - 3000之間。

一般情況下我們可以默認評測機一秒內可以運行1e7條語句,當然這只是一個大概的估計,實際上每個服務器的性能不同,這個值都不同,但是一般都相差不大,差一個常數是正常的。

因此,我們可以這樣做一個對應,下面是時限1S的情況

 

O(N)         N最大在500W左右

O(NlogN)     N最大在20W左右

O(N^2)       N最大在2000左右

O(N^2logN)   N最大700在左右

O(N^3)       N最大在200左右

O(N^4)       N最大在50左右

O(2^N)       N最大在24左右

O(N!)        N最大在10左右

如果是2S、3S對應的乘以2和3就可以。

 

特殊技巧:如果發現自己設計的算法不能題目要求的時限內解決問題,不要着急,可以先把這道題留一下,繼續做其他題,然後看一下排行榜,有多少人過了這道題,如果過的人多,那麼說明這道題可能數據比較水,直接暴力做,不要怕複雜度的問題,因爲出題人可能偷懶或者失誤了導致數據很水。考研機試的題目數據大部分情況都比較水,所以不要被複雜度嚇唬住了,後面的章節會教大家面對不會更好的算法那來解決題目的時候,如何用優雅的技巧水過去。

 

舉個簡單的例子

題目要求你對10W個數進行排序

假設你只會冒泡排序,但是冒泡排序很明顯複雜度太高了,但是有可能出題人偷懶,他構造測試數據最多隻有100個,根本沒有10W個,那麼你就可以用冒泡排序通過這道題。

但是這種情況比較少見,一般至少都會有一組極限數據,所以可以先把這道題放着做其他題,然後再看看其他人能不能通過,如果很多人都過了,那麼你就可以暴力試一下。

 

特別注意:空間複雜度一般不會限制,如果遇到了再想辦法優化空間。

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

1.8 C++ STL的使用

 

C++的算法頭文件裏有很多很實用的函數,我們可以直接拿來用。

#include <algorithm>

 

排序

sort()函數:依次傳入三個參數,要排序區間的起點,要排序區間的終點+1,比較函數。比較函數可以不填,則默認爲從小到大排序。

 

使用示例

  1. #include <bits/stdc++.h>  
  2. using namespace std;  
  3.   
  4. int a[105];  
  5. int main() {  
  6.     int n;  
  7.     scanf("%d", &n);  
  8.     for (int i = 0; i < n; i++) {  
  9.         scanf("%d", &a[i]);  
  10.     }  
  11.     sort(a, a+n);  
  12.     for (int i = 0; i < n; i++)  
  13.         printf("%d ", a[i]);  
  14.     return 0;  
  15. }  

 

查找

lower_bound()函數

upper_bound()函數

lower_bound( )和upper_bound( )都是利用二分查找的方法在一個排好序的數組中進行查找的。

 

 

從小到大的排序數組中,

lower_bound( begin,end,num):從數組的begin位置到end-1位置二分查找第一個大於或等於num的數字,找到返回該數字的地址,不存在則返回end。通過返回的地址減去起始地址begin,得到找到數字在數組中的下標。

upper_bound( begin,end,num):從數組的begin位置到end-1位置二分查找第一個大於num的數字,找到返回該數字的地址,不存在則返回end。通過返回的地址減去起始地址begin,得到找到數字在數組中的下標。

 

從大到小的排序數組中,重載lower_bound()和upper_bound()

lower_bound( begin,end,num,greater<type>() ):從數組的begin位置到end-1位置二分查找第一個小於或等於num的數字,找到返回該數字的地址,不存在則返回end。通過返回的地址減去起始地址begin,得到找到數字在數組中的下標。

upper_bound( begin,end,num,greater<type>() ):從數組的begin位置到end-1位置二分查找第一個小於num的數字,找到返回該數字的地址,不存在則返回end。通過返回的地址減去起始地址begin,得到找到數字在數組中的下標。

 

使用示例

  1. #include<bits/stdc++.h>  
  2. using namespace std;  
  3.   
  4. int cmp(int a,int b){  
  5.     return a>b;  
  6. }  
  7. int main(){  
  8.     int num[6]={1,2,4,7,15,34};  
  9.     sort(num,num+6);  //按從小到大排序  
  10.     int pos1=lower_bound(num,num+6,7)-num;      
  11.     //返回數組中第一個大於或等於被查數的值  
  12.     int pos2=upper_bound(num,num+6,7)-num;      
  13.     //返回數組中第一個大於被查數的值  
  14.     cout<<pos1<<" "<<num[pos1]<<endl;  
  15.     cout<<pos2<<" "<<num[pos2]<<endl;  
  16.     sort(num,num+6,cmp);       //按從大到小排序  
  17.     int pos3=lower_bound(num,num+6,7,greater<int>())-num;    
  18.     //返回數組中第一個小於或等於被查數的值  
  19.     int pos4=upper_bound(num,num+6,7,greater<int>())-num;    
  20.     //返回數組中第一個小於被查數的值  
  21.     cout<<pos3<<" "<<num[pos3]<<endl;  
  22.     cout<<pos4<<" "<<num[pos4]<<endl;  
  23.     return 0;  
  24. }  

 

優先隊列

通過priority_queue<int> q來定義一個儲存整數的空的priority_queue。當然priority_queue可以存任何類型的數據,比如priority_queue<string> q等等。

示例代碼

  1. #include <iostream>  
  2. #include <queue>  
  3. using namespace std;  
  4. int main() {  
  5.     priority_queue<int> q;//定義一個優先隊列  
  6.     q.push(1);//入隊  
  7.     q.push(2);  
  8.     q.push(3);  
  9.     while (!q.empty()) {//判讀隊列不爲空  
  10.         cout << q.top() << endl;//隊首元素  
  11.         q.pop();//出隊  
  12.     }  
  13.     return 0;  
  14. }  

 

 

 

 

C++的STL標準模板庫是一個非常重要的東西,可以極大的幫助你更快速解決題目。

 

vector

通過vector<int> v來定義一個儲存整數的空的vector。當然vector可以存任何類型的數據,比如vector<string> v等等。

 

示例代碼

 

  1. #include <iostream>    
  2. #include <vector>    
  3. using namespace std;    
  4. int main() {    
  5.     vector<int> v;//定義一個空的vector  
  6.     for (int i = 1; i <= 10; ++i) {    
  7.         v.push_back(i * i); //加入到vector中  
  8.     }    
  9.     for (int i = 0; i < v.size(); ++i) {    
  10.         cout << v[i] << " ";  //訪問vecotr的元素  
  11.     }    
  12.     cout << endl;    
  13.     return 0;    
  14. }    

 

queue

 

通過queue<int> q來定義一個儲存整數的空的queue。當然queue可以存任何類型的數據,比如queue<string> q等等。

示例代碼

 

  1. #include <iostream>  
  2. #include <queue>  
  3. using namespace std;  
  4. int main() {  
  5.     queue<int> q;//定義一個隊列  
  6.     q.push(1);//入隊  
  7.     q.push(2);  
  8.     q.push(3);  
  9.     while (!q.empty()) {//當隊列不爲空  
  10.         cout << q.front() << endl;//取出隊首元素  
  11.         q.pop();//出隊  
  12.     }  
  13.     return 0;  
  14. }  

 

 

stack

通過stack<int> S來定義一個全局棧來儲存整數的空的stack。當然stack可以存任何類型的數據,比如stack<string> S等等。

示例代碼

  1. #include <iostream>  
  2. #include <stack>  
  3. using namespace std;  
  4. stack<int> S;//定義一個棧  
  5. int main() {  
  6.     S.push(1);//入棧  
  7.     S.push(10);  
  8.     S.push(7);  
  9.     while (!S.empty()) {//當棧不爲空  
  10.       cout << S.top() << endl;//輸出棧頂元素  
  11.       S.pop();//出棧  
  12.     }  
  13.     return 0;  
  14. }  

 

map

通過map<string, int> dict來定義一個key:value映射關係的空的map。當然map可以存任何類型的數據,比如map<int, int> m等等。

 

示例代碼

  1. #include <iostream>  
  2. #include <string>  
  3. #include <map>  
  4. using namespace std;  
  5. int main() {  
  6.     map<string, int> dict;//定義一個map  
  7.     dict["Tom"] = 1;//定義映射關係  
  8.     dict["Jone"] = 2;  
  9.     dict["Mary"] = 1;  
  10.     if (dict.count("Mary")) {//查找map  
  11.         cout << "Mary is in class " << dict["Mary"];  
  12.     }  
  13.     //使用迭代器遍歷map的key和value  
  14.     for (map<string, int>::iterator it = dict.begin(); it != dict.end(); ++it) {  
  15.         cout << it->first << " is in class " << it->second << endl;  
  16.     }  
  17.     dict.clear();//清空map  
  18.     return 0;  
  19. }  

 

set

通過set<string> country來定義一個儲存字符串的空的set。當然set可以存任何類型的數據,比如set<int> s等等。

 

示例代碼

  1. #include <iostream>  
  2. #include <set>  
  3. using namespace std;  
  4. int main() {  
  5.     set<string> country;//定義一個存放string的集合  
  6.     country.insert("China");//插入操作  
  7.     country.insert("America");  
  8.     country.insert("France");  
  9.     set<string>::iterator it;  
  10.     //使用迭代器遍歷集合元素  
  11.     for (it = country.begin(); it != country.end(); ++it) {  
  12.         cout << * it  << " ";  
  13.     }  
  14.     cout << endl;  
  15.     country.erase("American");//刪除集合內的元素  
  16.     country.erase("England");  
  17.     if (country.count("China")) {//統計元素個數  
  18.         cout << "China in country." << endl;  
  19.     }  
  20.     country.clear();//清空集合  
  21.     return 0;  
  22. }  

 

1.9多組輸入的問題

對有的題目來說,可能需要多組輸入。

多組輸入是什麼意思呢?一般的題目我們輸入一組數據,然後直接輸出程序就結束了,但是多組輸入的話要求我們可以循環輸入輸出結果。

 

例題:

輸入兩個數,輸出兩個數的和,要求多組輸入。

樣例輸入

1 2

3 7

10 24

樣例輸出

3

10

34

 

C循環讀入代碼如下

  1. #include <bits/stdc++.h>  
  2. using namespace std;  
  3.   
  4. int main() {  
  5.     int a, b;  
  6.     while (scanf("%d%d", &a, &b) != EOF) {  
  7.         printf("%d\n", a+b);  
  8.     }  
  9.     return 0;  
  10. }  

 

特別注意:不能使用while(1)這樣死循環,!=EOF的意思一直讀取到文件末尾(End of file)

另外,多組輸入一定要注意初始化問題,數組和變量的初始化要放在while循環內,否則上一次的運算的結果會影響當前的結果。

 

C++循環讀入代碼如下

  1. #include <bits/stdc++.h>  
  2. using namespace std;  
  3.   
  4. int main() {  
  5.     int a, b;  
  6.     while (cin >> a >> b) {  
  7.         cout << a + b << endl;  
  8.     }  
  9.     return 0;  
  10. }  

 

Java循環讀入代碼如下

  1. Scanner stdin = new Scanner(System.in);  
  2. while (stdin.hasNext()) {  
  3.     String s = stdin.next();  
  4.     int n = stdin.nextInt();  
  5.     double b = stdin.nextDouble();  
  6. }  

 

Python循環讀入代碼如下

  1. while True:  
  2.     try:  
  3.         a, b = map(int, input().split())  
  4.         c = a+b  
  5.         print(c)  
  6.     except: #讀到文件末尾拋出異常結束循環  
  7.         break  

 

 

 

 

 

 

 

 

 

第二章 入門經典

 

我們根據全國上百所院校的歷年真題進行分析,總結了其中常見的題型,最常考的知識點。

學會這一章,在機試難度低的學校基本上可以拿到60-80分左右的成績,在機試難度中等的學校,也可拿到40-60分左右的成績,在機試難度高的學校亦可將簽到題做出來,拿到20-40分的成績。

所以,認真看完這一章的內容對你的幫助很大,加油,fighting!

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

2.1 簡單模擬

在考研機試中,有一類很常見的題型叫做簡單模擬。顧名思義,就是不需要去考慮什麼算法,直接按照題目的意思進行模擬計算就行。

 

促銷計算

題目描述:

某百貨公司爲了促銷,採用購物打折的優惠方法,每位顧客一次購物:在1000元以上者,按9.5折優惠;在2000以上者,按9折優惠;在3000以上者,按8.5折優惠;在5000以上者,按8折優惠;編寫程序,購物款數,計算並輸出優惠價。

輸入樣例#:

850

1230

5000

3560

輸出樣例#:

discount=1,pay=850

discount=0.95,pay=1168.5

discount=0.8,pay=4000

discount=0.85,pay=3026

題目來源:

DreamJudge 1091

 

解題分析:根據題目的意思,我們知道就是按照題意去進行打折優惠的計算,只需要判斷輸入的數值在哪個區間該用什麼優惠去計算就好了。

 

參考代碼

  1. #include <bits/stdc++.h>//萬能頭文件  
  2. using namespace std;  
  3.   
  4. int main() {  
  5.     double a;  
  6.     scanf("%lf", &a);  
  7.     //使用%g可以自動去掉小數點後多餘的0 如果是整數則顯示整數  
  8.     if (a < 1000) printf("discount=1,pay=%g\n", a);  
  9.     if (a >= 1000 && a < 2000) printf("discount=0.95,pay=%g\n", a*0.95);  
  10.     if (a >= 2000 && a < 3000) printf("discount=0.9,pay=%g\n", a*0.9);  
  11.     if (a >= 3000 && a < 5000) printf("discount=0.85,pay=%g\n", a*0.85);  
  12.     if (a >= 5000) printf("discount=0.8,pay=%g\n", a*0.8);  
  13.     return 0;  
  14. }  

 

題型總結

簡單模擬這類題目在考試中很常見,屬於送分簽到的題目。所有的考生,注意了,這類題必須會做。

對於簡單模擬這一類的題目,怎麼去練習提高呢?

很簡單,在DreamJudge上多做題就行了。那麼要達到什麼樣的標準呢?

如果你想拿高分甚至滿分,平時訓練的時候,這類題儘量要在8分鐘內解決。

如果你只是想拿個還不錯的成績,這類題AC的時間儘量不要超過15分鐘,一定要記住,最壞情況不能超過20分鐘,如果超過了,說明你平時做的題還是太少了。

在考試的過程中,大多數考生都會緊張,有些考生甚至會手抖,導致敲多某個字母,然後又調試半天,找半天錯,會導致比平時解決同樣難度的問題時長多一倍甚至更多,所以平時就要注意,做題千萬不能太慢了,不然沒有足夠的時間來解決其他的題目哦。

 

練習題目

DreamJudge 1133 求1到n的和

DreamJudge 1043 計算Sn

DreamJudge 1040 利潤提成

 

 

2.2 進制轉換類問題

進制轉換類的題目在絕大多數學校都是必考題目之一,這類題目的既基礎又靈活,能看出學生的編程功底,所以這類題目一定要掌握。

 

總的來說,跟進制相關的題目可以分爲以下幾種題型

 

1、反序數:輸入一個整數如123,將其轉換爲反序之後的整數321

2、10進制轉2進制:將一個10進制整數轉化爲一個2進制的整數

例如:7轉換爲111

3、10進制轉16進制:將一個10進制整數轉化爲一個18進制的整數

例如:10轉換爲A

4、10進制轉x進制:將一個10進制整數轉化爲一個x進制的整數

解析:這是前面兩個的一種通解,如果會前面兩種那麼這個自然也觸類旁通。

5、x進制轉10進制:將一個x進制整數轉化爲一個10進制的整數

解析:這是上一種情況的反例,看代碼之後相信也能容易理解。

6、x進制轉y進制:將一個x進制整數轉化爲一個y進制的整數

解析:遇到這種情況,可以拆解爲x先轉爲10進制,然後再將10進制轉爲y進制。

7、字符串轉浮點數

例如:有一串字符串31.25 將其轉換爲一個浮點數,可以先轉整數部分,再轉小數部分,最後相加即可。

8、浮點數轉字符串

例如:有一個浮點數23.45將其轉換爲一個字符串進行存儲,可以將整數和小數拆開再合併成一個字符串。

9、字符串轉整型和整形轉字符串

解析:直接用atoi函數和itoa函數即可。

 

 

 

反序數代碼

  1. #include <stdio.h>  
  2.   
  3. int main() {  
  4.     int n;  
  5.     scanf("%d", &n);  
  6.     int ans = 0;//將反序之後的答案存在這裏  
  7.     while (n > 0) {//將n逐位分解  
  8.         ans *= 10;  
  9.         ans += (n % 10);  
  10.         n /= 10;  
  11.     }  
  12.     printf("%d\n", ans);  
  13.     return 0;  
  14. }  

 

 

10進制轉x進制代碼(x小於10的情況)

  1. #include <stdio.h>  
  2.   
  3. int main() {  
  4.     int n, x;  
  5.     int s[105];  
  6.     //輸入10進制n 和 要轉換的進制x  
  7.     scanf("%d%d", &n, &x);  
  8.     int cnt = 0;//數組下標  
  9.     while (n > 0) {//將n逐位分解  
  10.         int w = (n % x);  
  11.         s[cnt++] = w;  
  12.         n /= x;  
  13.     }  
  14.     //反序輸出  
  15.     for (int i = cnt - 1; i >= 0; i--) {  
  16.         printf("%d", s[i]);  
  17.     }  
  18.     printf("\n");  
  19.     return 0;  
  20. }  

10進制轉x進制代碼(通用版)

  1. #include <stdio.h>  
  2.   
  3. int main() {  
  4.     int n, x;  
  5.     char s[105];//十進制以上有字符,所以用char存儲  
  6.     //輸入10進制n 和 要轉換的進制x  
  7.     scanf("%d%d", &n, &x);  
  8.     int cnt = 0;//數組下標  
  9.     while (n > 0) {//將n逐位分解  
  10.         int w = (n % x);  
  11.         if (w < 10) s[cnt++] = w + '0';//變成字符需要加'0'  
  12.         else s[cnt++] = (w - 10) + 'A';//如果轉換爲小寫則加'a'  
  13.         //如果大於10則從A字符開始  
  14.         n /= x;  
  15.     }  
  16.     //反序輸出  
  17.     for (int i = cnt - 1; i >= 0; i--) {  
  18.         printf("%c", s[i]);  
  19.     }  
  20.     printf("\n");  
  21.     return 0;  
  22. }  

 

 

x進制轉10進制(x爲2時)

  1. #include <stdio.h>  
  2. #include <string.h>  
  3.   
  4. int main() {  
  5.     char s[105];  
  6.     //輸入二進制字符串  
  7.     scanf("%s", &s);  
  8.     int ans = 0;//  
  9.     int len = strlen(s);  
  10.     for (int i = 0; i < len; i++) {  
  11.         if (s[i] == '0') {  
  12.             ans = ans * 2;  
  13.         }  
  14.         else {  
  15.             ans = ans * 2 + 1;  
  16.         }  
  17.     }  
  18.     printf("%d\n", ans);  
  19.     return 0;  
  20. }  

 

 

x進制轉10進制(通用版

  1. #include <stdio.h>  
  2. #include <string.h>  
  3.   
  4. int main() {  
  5.     char s[105];  
  6.     int x;  
  7.     //輸入X進制字符串 和 代表的進制x  
  8.     scanf("%s%d", &s, &x);  
  9.     int ans = 0;//  
  10.     int len = strlen(s);  
  11.     for (int i = 0; i < len; i++) {  
  12.         ans = ans * x;  
  13.         if (s[i] >= '0' && s[i] <= '9') ans += (s[i] - '0');  
  14.         else ans += (s[i] - 'A') + 10;  
  15.     }  
  16.     printf("%d\n", ans);  
  17.     return 0;  
  18. }  

 

 

x進制轉y進制(通用版)

  1. #include <stdio.h>  
  2. #include <string.h>  
  3.   
  4. int main() {  
  5.     char s[105];  
  6.     int x, y;  
  7.     //輸入二進制字符串 和 代表的進制x 以及要轉換的進制y  
  8.     scanf("%s%d%d", &s, &x, &y);  
  9.     int ans = 0;  
  10.     int len = strlen(s);  
  11.     for (int i = 0; i < len; i++) {  
  12.         ans = ans * x;  
  13.         if (s[i] >= '0' && s[i] <= '9') ans += (s[i] - '0');  
  14.         else ans += (s[i] - 'A') + 10;  
  15.     }  
  16.     char out[105];  
  17.     int cnt = 0;  
  18.     while (ans > 0) {  
  19.         int w = (ans % y);  
  20.         if (w < 10) out[cnt++] = w + '0';  
  21.         else out[cnt++] = (w-10) + 'A';  
  22.         ans /= y;  
  23.     }  
  24.     for (int i = cnt - 1; i >= 0; i--) {  
  25.         printf("%c", out[i]);  
  26.     }  
  27.     printf("\n");  
  28.     return 0;  
  29. }  

 

 

題型總結

這類題目任他千變萬化,本質上都是不變的。就是數位的拆解與合併,拆解很明顯就是兩步,先取模然後除取整,合併就是先乘後加。只要掌握了以上的幾類變化,不管題目如何變化,你都立於了不敗之地。

 

題目練習

DreamJudge 1454 反序數

DreamJudge 1178 進制轉換

DreamJudge 1259 進制轉換2

DreamJudge 1176 十進制和二進制

DreamJudge 1380 二進制數

DreamJudge 1417 八進制

DreamJudge 1422 進制轉換3

DreamJudge 1097 負二進制

 

 

2.3 排版類問題

排版類問題也是機試中經常出現的題目,這類題目主要考驗考生對代碼的掌控程度。表面上看起來很簡單,但是對於大部分沒有認真研究過的同學來學,這些題可能會搞半天才能搞出來。

 

總的來說,排版類的題目可以以下幾種題型爲代表。

  1. 輸出字符棱形 DreamJudge 1473

這類題目的變形可以是輸出長方形、三角形、梯形等形狀。

2、旋轉數字輸出

3、矩陣順/逆指針旋轉

4、矩陣翻轉

這類題目的變形可以是軸對稱翻轉、中心對稱翻轉等。

5、楊輝三角形

6、2048問題

 

 

以上,我們選擇其中輸出字符棱形楊輝三角形進行詳細講解,其他題型我們給出解題思路以及題目編號,大家可以在本節後面的練習題目裏找到並完成。如果自己無法理解並完成題目,請加入我們的機試交流羣進行提問交流。

 

字符棱形

題目描述:

輸入一個整數n表示棱形的對角半長度,請你用*把這個棱形畫出來。

輸入:3

輸出:

  *

 ***

*****

 ***

  *

輸入樣例#:

1

輸出樣例#:

*

題目來源:

DreamJudge 1473

 

解題分析:對於這類題目,我們可以將它進行分解。從中間切開,上面一個三角形,下面一個三角形。那麼問題就轉化爲了如何輸出三角形,我們可以利用兩個for循環控制來輸出三角形。

 

參考代碼

  1. #include <stdio.h>  
  2.   
  3. int main() {  
  4.     int n;  
  5.     scanf("%d", &n);  
  6.     //上三角  
  7.     for (int i = 1; i <= n; i++) {  
  8.         for (int j = 1; j <= n - i; j++) {  
  9.             printf(" ");  
  10.         }  
  11.         for (int j = n - i + 1; j < n + i; j++) {  
  12.             printf("*");  
  13.         }  
  14.         printf("\n");  
  15.     }  
  16.     //下三角  下三角只需要將上三角反過來輸出就行  
  17.     for (int i = n - 1; i >= 1; i--) {  
  18.         for (int j = 1; j <= n - i; j++) {  
  19.             printf(" ");  
  20.         }  
  21.         for (int j = n - i + 1; j < n + i; j++) {  
  22.             printf("*");  
  23.         }  
  24.         printf("\n");  
  25.     }  
  26.     return 0;  

 

 

楊輝三角形

題目描述:

提到楊輝三角形.大家應該都很熟悉.這是我國宋朝數學家楊輝在公元1261年著書《詳解九章算法》提出的。 1 1 1 1 2 1 1 3 3 1 1 4 6 4 1 1 5 10 10 5 1 1 6 15 20 15 6 1 我們不難其規律: S1:這些數排列的形狀像等腰三角形,兩腰上的數都是1 S2:從右往左斜着看,第一列是1,1,1,1,1,1,1;第二列是,1,2,3,4,5,6;第三列是1,3,6,10,15;第四列是1,4,10,20;第五列是1,5,15;第六列是1,6……。 從左往右斜着看,第一列是1,1,1,1,1,1,1;第二列是1,2,3,4,5,6……和前面的看法一樣。我發現這個數列是左右對稱的。 S3:上面兩個數之和就是下面的一行的數。 S4:這行數是第幾行,就是第二個數加一。…… 現在要求輸入你想輸出楊輝三角形的行數n; 輸出楊輝三角形的前n行.

輸入描述:

輸入你想輸出楊輝三角形的行數n(n<=20);當輸入0時程序結束.

輸出描述:

對於每一個輸入的數,輸出其要求的三角形.每兩個輸出數中間有一個空格.每輸完一個三角形換行.

輸入樣例#:

5

輸出樣例#:

1

1 1

1 2 1

1 3 3 1

1 4 6 4 1

題目來源:

DreamJudge 1062

 

解題分析:這是一道特別經典的題目,我們只需要按照題意用二維數組去計算即可。對於任意一個數a[i][j],都有a[i][j] = a[i-1][j] + a[i-1][j-1];

 

參考代碼

  1. #include <stdio.h>  
  2. int main() {  
  3.     int a[21][21] = {0};//數組裏的所有值初始化爲0  
  4.     int n;  
  5.     while (scanf("%d", &n) != EOF) {  
  6.         if (n == 0) break;  
  7.         a[1][1] = 1;  
  8.         for (int i = 2; i <= n; i++) {  
  9.             for (int j = 1; j <= i; j++) {  
  10.                 a[i][j] = a[i-1][j] + a[i-1][j-1];  
  11.             }  
  12.         }  
  13.         for (int i = 1; i <= n; i++) {  
  14.             for (int j = 1; j <= i; j++) {  
  15.                 printf("%d ", a[i][j]);  
  16.             }  
  17.             printf("\n");  
  18.         }  
  19.     }  
  20.     return 0;  
  21. }  

 

 

題型總結:這類題目儘量在平時練習,解法主要就是把一個大問題進行分解,一部分一部分的實現。在考試的時候遇到,千萬不要急,將問題進行分解,找到其中的規律,然後再寫出來。當然,如果平時就有練習,那就不用擔心了。

 

 

 

 

 

 

練習題目

DreamJudge 1392 楊輝三角形 - 西北工業大學

DreamJudge 1377 旋轉矩 - 北航

DreamJudge 1216 旋轉方陣

DreamJudge 1221 旋轉矩陣

DreamJudge 1472 2048遊戲

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

2.4 日期類問題

日期類的題目也是常考的題目,這類題目一般都爲以下幾種考法。

 

1、判斷某年是否爲閏年

2、某年某月某日是星期幾

變形問法:某日期到某日期之間有多少天

3、某天之後x天是幾月幾日

4、10:15分之後x分鐘是幾點幾分

變形問法:某點到某點之間有多少分或多少秒

 

注意輸入時候一般用scanf解析輸入值

如:2019-11-8 2019-11-08 2019/11/8 10:10

  1. int year, month, day;  
  2. scanf("%d-%d-%d", &year, &month, &day);  
  3. scanf("%d/%d/%d", &year, &month, &day);  
  4. int hour, minute;  
  5. scanf("%d:%d", &hour, &minute);  

 

 

日期

題目描述:

定義一個結構體變量(包括年、月、日),編程序,要求輸入年月日,計算並輸出該日在本年中第幾天。

輸入描述:

輸輸入三個整數(並且三個整數是合理的,既比如當輸入月份的時候應該在1 至12 之間,不應該超過這個範圍)否則輸出Input error!

輸出描述:

輸出一個整數.既輸入的日期是本月的第幾天。

輸入樣例#:

1985 1 20

2006 3 12

輸出樣例#:

20

71

題目來源:

DreamJudge 1051

 

 

解題分析:這個題目的考點在於兩個地方,一個是每個月的天數都不一樣,另一個是2月如果是閏年則多一天,最後我們還要判斷輸入的日期是否存在,如果不存在則輸出Input error!

 

參考代碼

  1. #include <stdio.h>  
  2.   
  3. struct node {  
  4.     int year, month, day;  
  5. }p;  
  6. int f[13] = {0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};  
  7. int main() {  
  8.     while (scanf("%d%d%d", &p.year, &p.month, &p.day) != EOF) {  
  9.         //判斷是否閏年  
  10.         if ((p.year%400== 0)||(p.year%4==0)&&(p.year%100!=0)) {  
  11.             f[2] = 29;  
  12.         }  
  13.         else f[2] = 28;  
  14.         int flag = 0;  
  15.         //判斷月份輸入是否合法  
  16.         if (p.month < 1 || p.month > 12) flag = 1;  
  17.         //判斷天的輸入是否合法  
  18.         for (int i = 1; i <= 12; i++) {  
  19.             if (p.day < 0 || p.day > f[i]) {  
  20.                 flag = 1;  
  21.             }  
  22.         }  
  23.         if (flag) {  
  24.             printf("Input error!\n");  
  25.             continue;  
  26.         }  
  27.         int ans = p.day;  
  28.         for (int i = 1; i < p.month; i++) {  
  29.             ans += f[i];  
  30.         }  
  31.         printf("%d\n", ans);  
  32.     }  
  33.     return 0;  
  34. }  

 

 

題型總結

日期類的題目就是要特別注意閏年的判斷,這些題目一般都是考察代碼細節的把握,時間類的題目注意時間的轉換,1天=24小時,1小時=60分,1分=60秒。

 

特別注意:一天之內時針和分針會重合22次,而不是24次。

 

 

 

 

 

 

練習題目

DreamJudge 1011 日期

DreamJudge 1290 日期差值

DreamJudge 1410 打印日期

DreamJudge 1437 日期類

DreamJudge 1446 日期累加

DreamJudge 1053 偷菜時間表

 

2.5 字符串類問題

字符串類的問題也是各個院校必考的題型之一,基本上有以下這些考點:

  1. 統計字符個數
  2. 單詞首字母大寫
  3. 統計子串出現次數

解析:考察大家基礎的字符串遍歷能力。

  1. 文本加密/解密

解析:通過循環往後移動x位或直接給一個映射表是比較常見的考法。

  1. 文本中的單詞反序

解析:靈活使用string可以秒殺這類題目,當然也可以用字符串一步步解析。

  1. 刪除字符串(大小寫模糊)

解析:如果大小寫不模糊,那麼就是直接找到之後刪除。大小寫模糊的話,只是多一個判斷。

 

加密算法

題目描述:

編寫加密程序,加密規則爲:將所有字母轉化爲該字母后的第三個字母,即A->D、B->E、C->F、......、Y->B、Z->C。小寫字母同上,其他字符不做轉化。輸入任意字符串,輸出加密後的結果。

例如:輸入"I love 007",輸出"L oryh 007"

輸入描述:

輸入一行字符串,長度小於100。

輸出描述:

輸出加密之後的結果。

輸入樣例#:

I love 007

輸出樣例#:

L oryh 007

題目來源:

DreamJudge 1014

 

題目解析:這是一道很常見的加解密考法,往後移動3位是這道題的核心,我們只需要按照題意將大寫字母、小寫字母、和其他分開進行處理就可以,具體看代碼。

參考代碼

  1. #include <stdio.h>  
  2. #include <string.h>  
  3.   
  4. int main() {  
  5.     char s[105];  
  6.     gets(s);//輸入一行文本用gets  
  7.     int len = strlen(s);  
  8.     for (int i = 0; i < len; i++) {  
  9.         if (s[i] >= 'A' && s[i] <= 'Z') {  
  10.             s[i] += 3;  
  11.             if (s[i] > 'Z') s[i] -= 26;//溢出循環  
  12.         }  
  13.         else if (s[i] >= 'a' && s[i] <= 'z') {  
  14.             s[i] += 3;  
  15.             if (s[i] > 'z') s[i] -= 26;//溢出循環  
  16.         }  
  17.         else {  
  18.             continue;  
  19.         }  
  20.     }  
  21.     puts(s);  
  22.     return 0;  
  23. }  

練習題目

DreamJudge 1012 字符移動

DreamJudge 1292 字母統計

DreamJudge 1240 首字母大寫

DreamJudge 1394 統計單詞

DreamJudge 1027 刪除字符串2

 

2.6 排序類問題

排序類的問題基本上是每個學校必考的知識點,所以它的重要性不言而喻。

如果你在網上一查,或者看數據結構書,十幾種排序算法可以把你嚇的魂不守舍。表面上看各種排序都有其各自的特點,那是不是我們需要掌握每一種排序呢?

答案自然是否定的。我們一種排序也不需要掌握,你需要會用一個sort函數就可以了,正所謂一個sort走天下。

 

sort函數本質上是封裝了快速排序,但是它做了一些優化,所以你只管用它就行了。

複雜度爲:nlogn

所以sort可以對最大30W個左右的元素進行排序,可以應對考研機試中的99.9%的情況。

 

sort函數的用法

sort()函數:依次傳入三個參數,要排序區間的起點,要排序區間的終點+1,比較函數。比較函數可以不填,則默認爲從小到大排序。

 

sort函數有兩個常見的應用場景

  1. 自定義函數排序
  2. 多級排序

 

 

成績排序

題目描述:

輸入任意(用戶,成績)序列,可以獲得成績從高到低或從低到高的排列,相同成績都按先錄入排列在前的規則處理。

示例:

jack      70

peter     96

Tom       70

smith     67

從高到低  成績

peter     96

jack      70

Tom       70

smith     67

從低到高

smith     67

jack      70

Tom      70

peter     96

輸入描述:

輸入多行,先輸入要排序的人的個數,然後輸入排序方法0(降序)或者1(升序)再分別輸入他們的名字和成績,以一個空格隔開

輸出描述:

按照指定方式輸出名字和成績,名字和成績之間以一個空格隔開

輸入樣例#:

3

0

fang 90

yang 50

ning 70

輸出樣例#:

fang 90

ning 70

yang 50

題目來源:

DreamJudge 1151

 

題目解析:這題唯一的一個考點在於穩定排序,sort排序是不穩定的,排序之後相對次序有可能發生改變。解決這個問題有兩個方法,一個是用stable_sort函數,它的用法和sort一樣,但是它是穩定的,所以如果我們遇到有穩定的需求的排序時,可以用它。另一個方法是給每一個輸入增加一個遞增的下標,然後二級排序,當值相同時,下標小的排在前面。

 

參考代碼(穩定排序)

  1. #include <bits/stdc++.h>  
  2. using namespace std;  
  3.   
  4. struct Student {  
  5.     string name;  
  6.     int grade;  
  7. }stu[1005];  
  8. //從大到小排序  
  9. bool compareDesc(Student a,Student b) {  
  10.     return a.grade > b.grade;  
  11. }  
  12. //從小到大排序  
  13. bool compareAsc(Student a,Student b) {  
  14.     return a.grade < b.grade;  
  15. }  
  16. int main() {  
  17.     int n,order;  
  18.     while(cin>>n) {  
  19.         cin>>order;  
  20.         for(int i=0;i<n;i++) {  
  21.             cin>>stu[i].name>>stu[i].grade;  
  22.         }  
  23.         if(order==0)  
  24.             stable_sort(stu,stu+n,compareDesc);  
  25.         else  
  26.             stable_sort(stu,stu+n,compareAsc);  
  27.         for(int i=0;i<n;i++) {  
  28.             cout<<stu[i].name<<" "<<stu[i].grade<<endl;  
  29.         }  
  30.     }  
  31.     return 0;  
  32. }  

 

參考代碼(標記id)

  1. #include <bits/stdc++.h>  
  2. using namespace std;  
  3.   
  4. struct Student {  
  5.     string name;  
  6.     int grade, id;  
  7. }stu[1005];  
  8. //從大到小排序  
  9. bool compareDesc(Student a,Student b) {  
  10.     if (a.grade == b.grade) return a.id < b.id;  
  11.     return a.grade > b.grade;  
  12. }  
  13. //從小到大排序  
  14. bool compareAsc(Student a,Student b) {  
  15.     if (a.grade == b.grade) return a.id < b.id;  
  16.     return a.grade < b.grade;  
  17. }  
  18. int main() {  
  19.     int n,order;  
  20.     while(cin>>n) {  
  21.         cin>>order;  
  22.         for(int i=0;i<n;i++) {  
  23.             cin>>stu[i].name>>stu[i].grade;  
  24.             stu[i].id = i;//通過標記ID進行判斷  
  25.         }  
  26.         if(order==0)  
  27.             sort(stu,stu+n,compareDesc);  
  28.         else  
  29.             sort(stu,stu+n,compareAsc);  
  30.         for(int i=0;i<n;i++) {  
  31.             cout<<stu[i].name<<" "<<stu[i].grade<<endl;  
  32.         }  
  33.     }  
  34.     return 0;  
  35. }  

 

 

 

 

 

排序

題目描述:

輸入n個數進行排序,要求先按奇偶後按從小到大的順序排序。

輸入描述:

第一行輸入一個整數n,表示總共有多少個數,n<=1000。

第二行輸入n個整數,用空格隔開。

輸出描述:

輸出排序之後的結果。

輸入樣例#:

8

1 2 3 4 5 6 7 8

輸出樣例#:

1 3 5 7 2 4 6 8

題目來源:

DreamJudge 1010

 

題目解析:題目要求我們按照奇數在前偶數在後的排序方法,同爲奇數或同爲偶數再從小到大排序。我們有兩種簡便的方法可以解決這個問題,其一是我們將奇數和偶數分離開來,然後分別排好序,再合併在一起。其二是使用sort進行二級排序,這裏我們採用第二種方法進行演示。

 

參考代碼

  1. #include <bits/stdc++.h>  
  2. using namespace std;  
  3.   
  4. bool cmp(int a,int b){  
  5.     if(a % 2 == b % 2)//如果同奇同偶  
  6.         return a < b;//直接從小到大排序  
  7.     else//如果奇偶性不同  
  8.         return (a%2) > (b%2);//奇數在偶數前  
  9. }  
  10. int main() {  
  11.     int n;  
  12.     int a[1005] = {0};  
  13.     cin >> n;  
  14.     for (int i = 0; i < n; i++) {  
  15.         cin >> a[i];  
  16.     }  
  17.     sort(a, a+n, cmp);  
  18.     for(int i = 0; i < n; i++) {  
  19.         cout << a[i] << " ";  
  20.     }  
  21.     cout << endl;  
  22.     return 0;  

 

 

小結:由上面可以看出,只要我們掌握好sort的用法,不管什麼樣的花裏胡哨的排序,我們都可以一力破之。

 

一些特殊的排序題

1、如果題目給的數據量很大,上百萬的數據要排序,但是值的區間範圍很小,比如值最大隻有10萬,或者值的範圍在1000W到1010W之間,對於這種情況,我們可以採用空間換時間的計數排序。

2、字符串的字典序排序是一個常見的問題,需要掌握,也是用sort。

下面兩種情況瞭解即可,追求滿分的同學需要掌握

3、如果題目給你一個數的序列,要你求逆序數對有多少,這是一個經典的問題,解法是在歸併排序合併是進行統計,複雜度可以達到nlogn。如果數據量小,直接冒泡排序即可。

4、如果題目讓你求top10,即最大或最小的10個數,如果數據量很大,建議使用選擇排序,也就是一個一個找,這樣複雜度比全部元素排序要低。

5、如果題目給的數據量有幾百萬,讓你從中找出第K大的元素,這時候sort是會超時的。解法是利用快速排序的劃分的性質,進入到其中一個分支繼續尋找,

 

以上都是一些數據很特殊且數據量非常大的情況下的解決方案。

 

 

 

練習題目

 

DreamJudge 1106 排序2

DreamJudge 1159 成績排序2.0

DreamJudge 1217 國名排序

DreamJudge 1227 日誌排序

DreamJudge 1248 整數奇偶排序

DreamJudge 1254 字符串排序

DreamJudge 1255 字符串排序2

DreamJudge 1261 字符串排序3

DreamJudge 1294 後綴子串排序

DreamJudge 1310 奧運排序問題

DreamJudge 1338 EXCEL排序

DreamJudge 1360 字符串內排序

DreamJudge 1399 排序 - 華科

DreamJudge 1400 特殊排序

DreamJudge 1404 成績排序 - 華科

DreamJudge 1412 大整數排序

 

 

 

 

 

 

 

2.7 查找類問題

查找是一類我們必須掌握的算法,它不僅會在題目中直接考察,同時也可能是其他算法中的重要組成部分。本章中介紹的查找類問題都是單獨的基礎查找問題,對於這類基礎查找的問題,我們應該將它完全掌握。

 

查找類題目一般有以下幾種考點

  1. 數字查找給你一堆數字,讓你在其中查找x是否存在

題目變形:如果x存在,請輸出有幾個。

  1. 字符串查找給你很多個字符串,讓你在其中查找字符串s是否存在

 

順序查找就不說了,這個大家會。

 

什麼時候不能用順序查找呢?

很明顯,當滿足下面這種情況的時候

  1. 數據量特別大的時候,比如有10W個元素。
  2. 查詢次數很多的時候,比如要查詢10W次。

 

遇到這類題大多數人的想法是先sort排序,然後二分查找,這是一個很常規的解決這類問題的方法。

但是,我們不推薦你這麼做,我們有更簡單易用且快速的方法。我們推薦你瞭解並使用map容器。

 

前面介紹過map,它是STL的一種關聯式容器,它的底層是紅黑樹實現的,也就意味着它的插入和查找操作都是log級別的。

相信每一個用過map的同學,都會情不自禁的說一句,map真香!

 

 

 

查找學生信息2

題目描述:

輸入N個學生的信息,然後進行查詢。

輸入描述:

輸入的第一行爲N,即學生的個數(N<=1000)

接下來的N行包括N個學生的信息,信息格式如下:

01 李江 男 21

02 劉唐 男 23

03 張軍 男 19

04 王娜 女 19

然後輸入一個M(M<=10000),接下來會有M行,代表M次查詢,每行輸入一個學號,格式如下:

02

03

01

04

輸出描述:

輸出M行,每行包括一個對應於查詢的學生的信息。

如果沒有對應的學生信息,則輸出“No Answer!”

輸入樣例#:

4

01 李江 男 21

02 劉唐 男 23

03 張軍 男 19

04 王娜 女 19

5

02

03

01

04

03

輸出樣例#:

02 劉唐 男 23

03 張軍 男 19

01 李江 男 21

04 王娜 女 19

03 張軍 男 19

題目來源:

DreamJudge 1476

 

題目解析:對於這類查詢量大的題目,我們有兩種方法來解決這個問題。第一是將學號先排好序,然後使用二分查找,但是很多同學寫二分的時候容易出現問題,而且代碼量也比較大,我們不推薦這種做法。推薦大家使用map來解決這類問題,基本上map可以通過99.9%的這類題目。

 

參考代碼

  1. #include <bits/stdc++.h>  
  2. using namespace std;  
  3.   
  4. struct node{  
  5.     string num;  
  6.     string name;  
  7.     string sex;  
  8.     int age;  
  9. };  
  10. int main(){  
  11.     int n,q;  
  12.     map<string, node> M;//定義一個map映射  
  13.     while(scanf("%d", &n)!=EOF){  
  14.         for(int i=0;i<n;i++){  
  15.             node tmp;  
  16.             cin>>tmp.num>>tmp.name>>tmp.sex>>tmp.age;  
  17.             M[tmp.num] = tmp;//將學號指向對應的結構體  
  18.         }  
  19.         scanf("%d", &q);  
  20.         for(int i=0;i<q;i++){  
  21.             string num;  
  22.             cin>>num;  
  23.             if((M.find(num))!=M.end())//find查找 如果找不到則返回末尾  
  24.                 cout<<M[num].num<<" "<<M[num].name<<" "<<M[num].sex<<" "<<M[num].age<<endl;  
  25.             else  
  26.                 cout<<"No Answer!"<<endl;  
  27.         }  
  28.     }  
  29.     return 0;  
  30. }  

 

可以發現,用map解決這個題目的時候,不用去考慮字符串排序的問題,也不用想二分查找會不會寫出問題,直接用map,所有的煩惱都沒有了,而且它的複雜度和二分查找是一個量級的。

 

上面講的是一類靜態查找的問題,實際中爲了增加思維難度或代碼難度,會經過一定的改變變成動態查找問題。

 

動態查找問題

題目描述:

有n個整數的集合,想讓你從中找出x是否存在。

輸入描述:

第一行輸入一個正整數n(n < 100000)

第二行輸入n個正整數,用空格隔開。

第三行輸入一個正整數q(q<100000),表示查詢次數。

接下來輸入q行,每行一個正整數x,查詢x是否存在。

輸出描述:

如果x存在,請輸出find,如果不存在,請輸出no,並將x加入到集合中。

輸入樣例#:

5

1 2 3 4 5

3

6

6

3

輸出樣例#:

no

find

find

題目來源:

DreamJudge 1477

 

題目解析:通過分析題目我們可以發現,這道題有一個特點就是,數的集合在不斷的改變。如果我們用先排序再二分的方法就會遇到困難,因爲加入新的數的時候我們需要去移動多次數組,才能將數插入進去,最壞情況每次插入都是O(n)的複雜度,這是無法接受的。當然也不是說就不能用這樣的方法來解決了,可以用離線的方法來解決這個問題,但是這樣做太複雜,不適合在考試中使用。那麼我們考慮用map來解決這個問題。

 

參考代碼

 

  1. #include <bits/stdc++.h>  
  2. using namespace std;  
  3.   
  4. int main(){  
  5.     int n,q,x;  
  6.     map<intint> M;//定義一個map映射  
  7.     scanf("%d", &n);  
  8.     for (int i = 0; i < n; i++) {  
  9.         scanf("%d", &x);  
  10.         M[x]++;//記錄集合中x有多少個  
  11.     }  
  12.     scanf("%d", &q);  
  13.     for (int i = 0; i < q; i++) {  
  14.         scanf("%d", &x);  
  15.         if (M[x] == 0) {//如果x的個數爲0  
  16.             printf("no\n");  
  17.             M[x]++;//將x加入到集合中  
  18.         }  
  19.         else printf("find\n");  
  20.     }  
  21.     return 0;  

 

看了上面的代碼,是不是發現用map來解決問題真是超級簡單。所以學會靈活使用map將能極大的拉近你和大佬之間的距離,我們一起來學map吧!

 

當然不是說二分查找就沒用了,我們也需要了解二分查找的原理,只不過。二分的前提是單調性,只要滿足單調性就可以二分,不論是單個元素還是連續區間。下面我們也給出一個基本的二分查找代碼,供大家參考。

 

  1. #include <bits/stdc++.h>  
  2. using namespace std;  
  3.   
  4. int a[10005];  
  5. int main(){  
  6.     int n,x;  
  7.     scanf("%d", &n);//輸入n個數  
  8.     for (int i = 1; i <= n; i++) {  
  9.         scanf("%d", &a[i]);  
  10.     }  
  11.     sort(a+1, a+1+n);//排序保持單調性  
  12.     scanf("%d", &x);//要查找的數x  
  13.     int l = 1, r = n;  
  14.     while (l < r) {  
  15.         int mid = (l + r) / 2;  
  16.         if (a[mid] == x) {  
  17.             printf("find\n");  
  18.             return 0;  
  19.         }  
  20.         if (a[mid] > x) {//如果x比中間數小  
  21.             r = mid - 1;//說明在左區間  
  22.         }  
  23.         else l = mid + 1;//否則在右區間內  
  24.     }  
  25.     printf("not find\n");  
  26.     return 0;  
  27. }  

 

 

 

練習題目

DreamJudge 1177 查找學生信息

DreamJudge 1388 查找1

DreamJudge 1387 查找 - 北郵

DreamJudge 1383 查找第K小數

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

2.8 貪心類問題

貪心類問題是很常見的考點,貪心算法更重要的是一種貪心的思想,它追求的是當前最優解,從而得到全局最優解。貪心類問題基本上算是必考題型之一,它能更好的考察出學生的思維能力以及對問題的分析能力,很多學校的出題人都非常愛出貪心類的題目。

 

貪心算法的定義:

貪心算法是指在對問題求解時,總是做出在當前看來是最好的選擇。也就是說,不從整體最優上加以考慮,只做出在某種意義上的局部最優解。

貪心算法不是對所有問題都能得到整體最優解,關鍵是貪心策略的選擇,選擇的貪心策略必須具備無後效性,即某個狀態以前的過程不會影響以後的狀態,只與當前狀態有關。

 

貪心可以很簡單,簡單到讓所有人一眼就能看出來該怎麼做。貪心也可以很難,難到讓你沒辦法去證明這樣貪心的正確性。所以要想解決貪心這類問題,主要還是看你的悟性,看你對題目的分析能力如何,下面我們舉例說明。

 

例子1:地上有3張紙幣,分別是5元、1元和10元,問你只能拿一張,最多能拿多少錢?

解析:很明顯,10元。

例子2:地上有n張紙幣,有1元的,有5元的,還要10元的,問你只能拿一張,最多能拿多少錢?

解析:很明顯,還是10元。

例子3:地上有很多紙幣,有a張1元的,有b張5元的,還要c張10元的,問你從中拿x張,最多能拿多少錢?

解析:大家應該都能想到,肯定是優先拿10元的,如果10元的拿完了,再拿5元的,最後纔會拿1元的。這就是貪心的思想,所以貪心其實是很容易想到的。

例子4:有n個整數構成的集合,現在從中拿出x個數來,問他們的和最大能是多少?

解析:相信大家都能想到,優先拿大的,從大到小一個個拿,這樣組成的和最大。那麼在解決這個問題之前,我們需要先排序,從大到小的排好序,然後將前x個數的和累加起來就是答案。

 

從上面幾個例子中,相信大家對貪心已經有了初步的瞭解。我們使用貪心的時候,往往需要先按照某個特性先排好序,也就是說貪心一般和sort一起使用。

 

喝飲料

題目描述:

商店裏有n中飲料,第i種飲料有mi毫升,價格爲wi。

小明現在手裏有x元,他想吃盡量多的飲料,於是向你尋求幫助,怎麼樣買才能吃的最多。

請注意,每一種飲料都可以只買一部分。

輸入描述:

有多組測試數據。

第一行輸入兩個非負整數x和n。

接下來n行,每行輸入兩個整數,分別爲mi和wi。

所有數據都不大於1000。

x和n都爲-1時程序結束。

輸出描述:

請輸出小明最多能喝到多少毫升的飲料,結果保留三位小數。

輸入樣例#:

233 6

6 1

23 66

32 23

66 66

1 5

8 5

-1 -1

輸出樣例#:

136.000

題目來源:

DreamJudge 1478

 

題目解析:通過分析之後我們可以發現,小明想要喝盡量多的飲料的話,肯定優先選擇性價比最高的飲料喝,也就是說1毫升的價格最低的飲料先喝,那麼我們就需要去比較,每種飲料1毫升的價格是多少。然後按照這個單價從低到高依次排序,然後一個一個往後喝,這樣可以保證小明能喝到最多的飲料。

 

參考代碼

  1. #include <bits/stdc++.h>  
  2. using namespace std;  
  3.   
  4. struct node {  
  5.     double w, m;  
  6. }p[1005];  
  7. bool cmp(node a, node b) {  
  8.     //按照每毫升的價格從低到高排序  
  9.     return a.w/a.m < b.w/b.m;  
  10. }  
  11. int main(){  
  12.     int n,x;  
  13.     while (scanf("%d%d", &x, &n) != EOF) {  
  14.         if (x == -1 && n == -1) break;  
  15.         for (int i = 1; i <= n; i++) {  
  16.             scanf("%lf%lf", &p[i].m, &p[i].w);  
  17.         }  
  18.         sort(p+1, p+1+n, cmp);  
  19.         double ans = 0;  
  20.         for (int i = 1; i <= n; i++) {  
  21.             if (x >= p[i].w) {//如果剩餘的錢能全買  
  22.                 ans += p[i].m;  
  23.                 x -= p[i].w;  
  24.             }  
  25.             else {//如果剩餘的錢買不完這種飲料  
  26.                 ans += (p[i].m*x/p[i].w);  
  27.                 break;//到這裏x已經爲0了  
  28.             }  
  29.         }  
  30.         printf("%.3lf\n", ans);  
  31.     }  
  32.     return 0;  

 

 

解題的通用步驟

1、建立數學模型來描述問題;

2、把求解的問題分成若干個子問題;

3、對每一子問題求解,得到子問題的局部最優解;

4、把子問題的局部最優解合成原來問題的一個解。

 

題型總結

貪心問題在很多機試難度低的學校,可以成爲壓軸題,也就是通過人數最少的題目。在機試難度高的學校也是中等難度及以上的題目,爲什麼明明貪心看起來這麼容易的題目,卻成爲大多數學生過不去的坎呢?原因有二,一是很多同學根本就沒有想到這個題目應該用貪心算法,沒能將題目抽象成數學模型來分析,簡單說就是沒有讀懂題目隱藏的意思。二是讀懂題了,知道應該是貪心算法解這個題目,但是排序的特徵點卻沒有找準,因爲不是所有題目都是這麼明顯的看出來從小到大排序,有的題目可能隱藏的更深,但是這種難度的貪心不常見。所以機試中的貪心題,你要你反應過來這是一個貪心,99%的情況下都能解決。

 

 

 

練習題目

DreamJudge 1307 組隊刷題

DreamJudge 1347 To Fill or Not to Fill

 

 

 

 

2.9 鏈表類問題

鏈表類問題屬於選讀章節,對於使用OJ測評的院校的同學來說,這類問題可以用數組來實現,沒有必要用鏈表去實現,寫起來慢不說,還容易出錯,所以我們一般都直接用數組來實現,反正最後OJ能AC就行,建議這類同學跳過本節或僅做了解即可。但是對於非OJ測評的院校來說,鏈表類問題可以說是必考的題型。

一般來說有以下三種常見考點

  1. 猴子報數

解析:循環鏈表建立之後,按照題意刪除節點。

  1. 兩個有序鏈表合併爲一個

解析:這個和兩個有序數組合併爲一個有序數組原理一樣。

  1. 鏈表排序

解析:使用冒泡排序進行鏈表排序,因爲冒泡排序是相鄰兩個元素進行比較交換,適合鏈表。

 

猴子報數

題目描述:

n個猴子圍坐一圈並按照順時針方向從1到n編號,從第s個猴子開始進行1到m的報數,報數到第m的猴子退出報數,從緊挨它的下一個猴子重新開始1到m的報數,如此進行下去知道所有的猴子都退出爲止。求給出這n個猴子的退出的順序表。

輸入描述:

有做組測試數據.每一組數據有兩行,第一行輸入n(表示猴子的總數最多爲100)第二行輸入數據s(從第s個猴子開始報數)和數據m(第m個猴子退出報數).當輸入0 0 0時表示程序結束.

輸出描述:

每組數據的輸出結果爲一行,中間用逗號間隔。

輸入樣例#:

10

2 5

5

2 3

0

0 0

輸出樣例#:

6,1,7,3,10,9,2,5,8,4

4,2,1,3,5

題目來源:

DreamJudge 1081

 

題目解析:我們需要創建一個首尾相連的循環鏈表,然後先走s步,再開始循環遍歷鏈表,每走m步刪除一個節點,知道鏈表中只能下一個節點時結束循環。只能一個節點的判斷條件是,它的下一個指針指向的是它,說明它自循環了。

 

  1. #include <stdio.h>  
  2. #include <malloc.h>  
  3. struct node {  
  4.     int num;  
  5.     struct node *next;  
  6. };  
  7. int n, s, m;  
  8. //創建循環鏈表  
  9. struct node* create() {  
  10.     struct node *head, *now, *pre;  
  11.     for (int i = 1; i <= n; i++) {  
  12.         now = (struct node *)malloc(sizeof(node));  
  13.         if (i == 1) {//第一個節點需要處理  
  14.             head = now;//頭結點指向第一個節點  
  15.             pre = now;//上一個節點也指向它  
  16.         }  
  17.         now->num = i;  
  18.         now->next = head;  
  19.         pre->next = now;  
  20.         pre = now;//將當然節點作爲上一個節點  
  21.     }  
  22.     return head;  
  23. };  
  24. //按照題目要求輸出  
  25. void print(struct node *head) {  
  26.     struct node *p;  
  27.     p = head;  
  28.     while (s--) {//先走s步  
  29.         p = p->next;  
  30.     }  
  31.     int i = 1;  
  32.     while (p != NULL) {  
  33.         if (p == p->next) {//只剩最後一個  
  34.             printf("%d\n", p->num);  
  35.             break;  
  36.         }//這裏有個小技巧 我們遍歷到滿足條件的上一個  
  37.         if ((i+1) % (m-1) == 0) {//然後輸出下一個  
  38.             printf("%d,", p->next->num);//這樣方便刪除  
  39.             p->next = p->next->next;//刪除下一個節點  
  40.         }  
  41.         p = p->next;  
  42.         i++;  
  43.     }  
  44. }  
  45. int main(){  
  46.     while (scanf("%d%d%d", &n, &s, &m) != EOF) {  
  47.         if (n==0&&s==0&&m==0) break;   
  48.         struct node *head;  
  49.         head = create();  
  50.         print(head);  
  51.     }  
  52.     return 0;  
  53. }  

 

練習題目

DreamJudge 1015 單鏈表

DreamJudge 1018 擊鼓傳花

DreamJudge 1025 合併鏈表

DreamJudge 1405 遍歷鏈表

 

第三章 數學

3.1 同模餘定理

3.2 最大公約數(GCD)

3.3 最小公倍數(LCM)

3.4 斐波那契數列

3.5 素數判定

3.6 素數篩選

3.7 分解素因數

3.8 二分快速冪

3.9 常見數學公式總結

3.10 規律神器OEIS

第四章 高精度問題

4.1 Python解法

4.2 Java解法

4.3 C/C++解法

第五章 數據結構

5.1 棧的應用

5.2 哈夫曼樹

5.3 二叉樹

5.4 二叉排序樹

5.5 hash算法

5.6 前綴樹

第六章 搜索

6.1 暴力枚舉

6.2 廣度優先搜索(BFS)

6.3 遞歸及其應用

6.4 深度優先搜索(DFS)

6.5 搜索剪枝技巧

6.6終極偏分技巧

第七章 圖論

7.1 理論基礎

7.2 圖的存儲

7.3 並查集

7.4 最小生成樹問題

7.5 最短路徑問題

7.6 拓撲排序

7.7 打印路徑類問題

第八章 動態規劃

8.1 遞推求解

8.2最大子段和

8.3 最長上升子序列(LIS)

8.4 最長公共子序列(LCS)

8.5 揹包類問題

8.6 記憶化搜索

8.7 字符串相關的動態規劃

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章