打表是一種典型的用空間換時間的技巧,一般指將所有可能需要用到的結果事先計算出來,這樣后面需要用到時就可以直接查表獲得。打表常見的用法有如下幾種:
1、在程序中一次性計算出所有需要用到的結果,之后的查詢直接取這些結果。
這個是最常用到的用法,例如在一個需要查詢大量Fibonacci數F(n)的問題中,顯然每次從頭開始計算是非常耗時的,對Q次查詢會產生O(nQ)的時間復雜度;而如果進行預處理,即把所有Fibonacci數預先計算並存在數組中,那么每次查詢就只需O(1)的時間復雜度,對Q次查詢就值需要O(n+Q)的時間復雜度(其中O(n)是預處理的時間)。
2、在程序B中分一次或多次計算出所有需要用到的結果,手工把結果寫在程序A的數組中,然后在程序A中就可以直接使用這些結果。
這種用法一般是當程序的一部分過程小號的時間過多,或是沒有想到好的算法,因此在另一個程序中使用暴力算法去i出結果,這樣就能直接在源程序中使用這些結果。例如對n皇后問題來說,如果使用的算法不夠好,就容易超時,而可以在本地用程序計算付出對所有n來說n皇后問題的方案數,然后把算出的結果直接卸載數組中,就可以根據題目輸入的n來直接輸出結果。
3、對一些感覺不會做的題目,先用暴力程序計算小范圍數據的結果,然后找規律,或許就能發現一些“蛛絲馬跡”。
這種用法在數據范圍非常大時候容易用到,因為這樣的題目可能不是用直接能想到的算法來解決的,而需要尋找一些規律才能得到結果。
例題:PAT乙級1044火星數字
火星人是以13進制計數的: 地球人的0被火星人稱為tret。 地球人數字1到12的火星文分別為:jan, feb, mar, apr, may, jun, jly, aug, sep, oct, nov, dec。 火星人將進位以后的12個高位數字分別稱為:tam, hel, maa, huh, tou, kes, hei, elo, syy, lok, mer, jou。 例如地球人的數字“29”翻譯成火星文就是“hel mar”;而火星文“elo nov”對應地球數字“115”。為了方便交流,請你編寫程序實現地球和火星數字之間的互譯。 輸入格式: 輸入第一行給出一個正整數N(<100),隨后N行,每行給出一個[0, 169)區間內的數字 —— 或者是地球文,或者是火星文。 輸出格式: 對應輸入的每一行,在一行中輸出翻譯后的另一種語言的數字。 輸入樣例: 4 29 5 elo nov tam 輸出樣例: hel mar may 115 13
思路:寫一個初始化函數,把所有的結果保存下來,在main函數中直接找我們所需要的數字即可。具體代碼如下:
#include <iostream> #include <string> #include <cstdio> #include <map> using namespace std; string unitDigit[13]={"tret","jan","feb","mar","apr","may","jun","jly","aug","sep","oct","nov","dec"}; string tenDigit[13]={"tret","tam","hel","maa","huh","tou","kes","hei","elo","syy","lok","mer","jou"}; string numToStr[170];//數字->火星文 map<string,int> strToNum;//火星文->數字 void init(){ for(int i=0;i<13;i++){ numToStr[i]=unitDigit[i];//個位是[0,12],十位為0 strToNum[unitDigit[i]]=i; numToStr[i*13]=tenDigit[i];//十位是[0,12],個位是0 strToNum[tenDigit[i]]=i*13; } //以下是除個位數和整十位數之外的轉換 for(int i=1;i<13;i++){//十位 for(int j=1;j<13;j++){//個位 string str=tenDigit[i]+" "+unitDigit[j]; numToStr[i*13+j]=str; strToNum[str]=i*13+j; } } } int main(){ init();//打表 int N; scanf("%d%*c",&N); for(int i=0;i<N;i++){ string str; getline(cin,str); if(str[0]>='0'&&str[0]<='9'){//數字 則轉換為int數字 int num=0; for(int i=0;i<str.size();i++){ num=num*10+(str[i]-'0'); } cout<<numToStr[num]<<endl; }else{ cout<<strToNum[str]<<endl; } } return 0; }