打表:是一種典型的用空間換時間的做法,一般指將所有可能需要用到的結果事先計算出來,這樣以後後面需要用到時就可以直接查表獲得。在什麼情況下我們需要打表?
(1)在程式中一次性計算出所有需要用到的結果,之後查詢直接取這些結果。
舉個例子,假如我們算fibonacci數中的f(n)我們假如需要算很多次q次 比如:(10^6),每次我們都是從頭開始算的,對於q次查詢就會產生(nq)的時間複雜度,但是如果我們提前把所有(足夠大的n,大於題上給的範圍)都事先算出來,並存在陣列中,那麼我們每次查詢就只需要o(1)的時間複雜度,q次查詢就只需要o(q+n)的時間複雜度,o(n)是預處理時間,
(2)在程式b中分一次或多次計算出所有需要用到的結果,手工把結果寫在程式a的陣列中,然後在程式a中就可以直接使用這些結果。
這種用法一般是當程式的一部分過程消耗的時間過多(比如你的dfs(搜尋),遞迴),或者是沒有想好的演算法,因此在另乙個程式中使用暴力演算法出結果,這樣就能直接在源程式中使用這些結果(記憶化搜尋,避免重複遞迴(搜尋),你已經搜過一次用乙個數儲存在陣列內,當下次再搜尋到這裡是直接呼叫這的值即可),比如對n皇后問題的方案數,如果飾演使用的演算法不夠好,就容易超時,而可以在本地程式計算出所有對n來說n皇后問題的方案數,然後把算出的結果儲存在陣列中,就可以根據題目輸入的n來直接找出結果。
每次判斷這個數是否為素數,如果是就存在陣列內,優點:太好想了,缺點:時間複雜度太高(n ^ 2)
1 #include2 #include3傻瓜打表using
namespace
std;
4int
main() 17}
18if
(flag) 21}
22for (int i = 0; i < k; i++)
25return0;
26 }
這個版本也很好想,我們算乙個數是否是素數,是不是要判斷它的因子,是否只是1和他本身,第一種傻瓜打表法我們從1 判斷 到了n 本身,但是實際上好像不需要哦,我們只需要判斷到 根號n就可以了。優點:稍微快了一點,缺點:時間複雜度還是(n^2)
1 #include2 #include3view codeusing
namespace
std;
4int
main() 17}
18if
(flag) 21}
22for (int i = 0; i < k; i++)
25return0;
26 }
我們想一想,我們上面的兩種是從數的本身去判斷是不是素數,那我們現在換一種方法。普通篩選法求素數-------埃拉託斯特尼篩法,出現乙個數,則把以這個數為因子的數都標記為合數。
如2,所以4,6,8 10....都標記為合數
如3,所以9,12,15.....都標記為合數
如4,所以16,20,24...都標記為合數
即,若i是素數,則從 j=i*i 開始,把 j+i , j+2i , j+3i .....都標記為合數 (因為2*i , 3*i,4*i,....(i-1)*i 分別是2,3,4,...i-1的的倍數,已經在i之前標記過,所以從j=i*i開始標記)篩法的思想是去除要求範圍內所有的合數,剩下的就是素數了,而任何合數都可以表示為素數的乘積,因此如果已知乙個數為素數,則它的倍數都為合數。篩選法求素數,優點:o(nloglogn),缺點:因為6在i==2時就被標記了,而在i==3的時候又被標記了一次,所以還是有改進的空間。
1 #include2 #include3高階版這種方法是可以優化的,6是不是2 的倍數, 6也是3 的倍數,當你去除2的倍數的時候已經把6去掉了,然後又去去除3的倍數,又去了一次6,這是不是重複計算了。using
namespace
std;
4#define max_num 10000000
5bool isprime[max_num + 10];6
7void
prim()
15for (int i = 2; i <= max_num; i++) 19}
20int
main()
我們知道合數可以由乙個質數數與另乙個合數相乘得到
而同時假設合數a=質數b×質數c×乙個數d
令e=c × d,假設b ≥ e,e為合數,令f=d × b
a=f × c ,其中c
即比乙個合數數大的質數和該合數的乘積可用乙個更大的合數和比其小的質數相乘得到(你從小的質數開始篩選,那麼我們就可以找出)
這也是if(!( i % prime[j]))break;的含義,這也是線性篩法算質數表的關鍵所在
1 #include2view codeusing
namespace
std;
3#define maxn 100000
4#define maxl 1000000
5int
prime[maxn];
6bool
check[maxl];78
intmain()
20 check[i * prime[j]] = 1; //
如果check[i*prime[j]]是已知素數的整數倍那一定是合數
21if ((i % prime[j]) == 0) //
如果i是乙個合數,而且i % prime[j] == 0
22break;23
}24}25
for (int i = 0; i < count; i++)
26 cout << prime[i] << "";
27}28return0;
29 }
素數篩法打表
篩法打素數表是一種高效的打表方法,具體做法是 先把n個自然數按次序排列起來。1不是質數,也不是合數,要划去。第二個數2是質數留下來,而把2後面所有能被2整除的數都劃去。2後面第乙個沒劃去的數是3,把3留下,再把3後面所有能被3整除的數都劃去。3後面第乙個沒劃去的數是5,把5留下,再把5後面所有能被5...
篩法素數打表方法
埃拉託斯特尼篩法,是一種西元前250年由古希臘數學家埃拉託斯特尼所提出的一種簡單檢定素數的演算法。給出要篩數值的範圍n,找出以內的素數。先用2去篩,即把2留下,把2的倍數剔除掉 再用下乙個質數,也就是3篩,把3留下,把3的倍數剔除掉 接下去用下乙個質數5篩,把5留下,把5的倍數剔除掉 不斷重複下去....
ACM 素數線性篩法(素數打表)
題目 include include int prime 700000 bool check 10000000 int num 1 int judge int y int j 0 while p j 1 j j i 0 while i j i j return1 int main int j 1 f...