在現實生活中使用演算法,是什麼感受?
可能很多OIER發現演算法在實際生活中沒什麼用(但可以吹牛)。
比方說,在一個有序數列中找一個數。假定數列已經確定(即不考慮讀入時儲存的時間),在OI中我們常常用二分法,效率為O(logn);然而實際生活中(即不用計算機),我們發現往往直接列舉一遍或是隨機化查詢,儘管理論上效率是O(n),但比二分查詢的人一般要快。這是為什麼呢?
經過上百次試驗和苦苦的思考,可以發現:這是顯然的。計算機計算mid值是O(1),查詢某個位置的數也是O(1),然而你手算不一定能達到這個效率;即使達到了mid值快速求解,查詢某個位置的數時,你也要列舉一遍找這個數O(mid),因為你事先不知道每個數的位置,這樣一來,二分效率就成了O(nlogn)。但是,如果事先把數列中每個數賦一個下標,在n較大時,二分效率應該是更高的。
但是我們也不能因此否認二分法啊,想一想,如果像猜數字那種給你有限次機會,二分法顯然是最佳策略,這也間接體現了二分法的高效率。(因為這時複雜度就是猜的次數而不是消耗時間了)
昨天上數學課時,講了二項式定理在求餘數中的應用,即a^k mod b。如果不用二項式定理,學OI的人一眼就看出這是快速冪了。快速冪的時間複雜度為O(logk),而如果直接暴力計算,複雜度是O(k),理論上看,快速冪應該更優。但是同樣不給你用計算機而手算的話,暴力計算(即一遍一遍乘過去,最後取mod)在數字較小時有時反而更快。其實原因也不難想,取mod在計算機看來複雜度是O(1),而對於我們就不是了。手算時列豎式除法,複雜度為O(n),其中n為數字十進位制位數。快速冪是邊乘邊取mod,複雜度就會更高。但如果只求a^k,快速冪又顯然更快了。
但是我們又會發現,即使忽略求餘數時的時間複雜度,無論是暴力還是快速冪,總不可能降到理論複雜度。其實原因也不難想,我們計算時採取列豎式計算,而在64位整數範圍內計算機乘法運算卻可以達到O(1)複雜度,這顯然是豎式計算達不到的(當然我們討論的是結果在64位整數範圍內的乘法,否則不可能手算:會頭破血流)。豎式計算相當於計算機計算時用高精度計算,這時複雜度已不是O(1),而是O(n^2),其中n為數字十進位制位數。故快速冪的總時間複雜度為O((lg(a)+lg(a)^2)*log(k)),暴力的複雜度為O(lg(a^k)+lg(a^k)*lg(a^k)*k),資料小時暴力較快。
當然,上面一切一切都還是進行了很多簡化。事實上,你手算中進行演算法的邏輯判斷等等,總比無腦算要耗掉更多時間。