快速求幂(Quick Exponentiation)
接觸ACM沒幾天,向各路大神求教,聽說ACM主要是研究算法,所以便開始了苦逼的算法學習之路。話不多說,RT所示,學習快速求冪。
在頭文件<math.h>或是<cmath>中,double pow( double x, double y );函數是用來快速求x^y,于是便從pow函數來說起,以下大體上是pow的函數代碼:
通過以上程序,2^5 = 2*2*2*2*2的流程中一共進行了4次乘法。試想若是大數2^99999999.......,這樣循環的算下來肯定要計算到猴年馬月。那么我們有什么辦法可以簡化我們的冪指運算呢?
?
分析數據
2^4=2^2 * 2^2;
2^5=2^2 * 2^2 * 2
2^6=2^3 * 2^3
2^7=2^3 * 2^3 * 2
……
x^n = x^(n/2) * x^(n/2) (n為偶數)
x^n = x^(n/2) * x^(n/2) * n (n為奇數)
?
顯然這種算法分析利用分治思想(divide and conquer)。通過這種方式,我們可以根據通項公式寫出遞歸函數求分制冪指運算的函數代碼:
由此我們以分治思想,減少了運算量。接下來,我們研究此遞歸代碼的一些細節。對于n/2,我們在二進制位運算中還有其他的處理方式,倘若一個數是二進制數,只要我們將該數右移一位(x>>1),即可對其真值除以2。也許你又會想,DG想表述的是什么意思,即使我把代碼中的n/2換成n>>1運算量有沒有改變,到底意義何在呢?我們從一個例子引出:
?問題:請求出3^999=?(問題目的在于感受不同求解方法的復雜程度)
?
分析:我們先調用最最基本的方式進行求解,即為求:3 * 3 * …… * 3(999個3),這樣一共要進行998次乘法運算。這種方法顯然是太麻煩,反復的遞歸,計算機心里定會默念“我靠,坑爹啊!”
?
接下來,我們使用簡單分制思想來做此題,這樣就可以大大簡少運算次數,使得計算次數僅為9次。但是,如果你也在學習ACM的話,你會懂得遞歸做法運行速度之慢。即使遞歸函數通俗易懂,即使寫法簡單,但是并不推薦。你若不信,我給大家舉一個簡單的例子:
?
利用歐幾里德算法(輾轉相除法)計算兩數的gcd(最大公約數)
遞歸形式:
非遞歸形式:
?
以上利用相同的思想進行求解a,b的gcd,但是效率有很大偏差,大家可以嘗試。
那么,還有什么方法來求解這個問題呢,接下來便是經典的快速求冪法。我們將3^999進行分解,即為:?(3 ^ 512) * (3 ^ 256) * (3 ^ 128) * (3 ^ 64) * (3 ^ 32) * (3 ^ 4) * (3 ^ 2) * 3。這時候,我們可以整理出3的指數部分形式:2^9+2^8+2^7+2^6+2^2+2^1+2^0。然后,我們再把999轉換成2進制為1111100111,2進制的轉換作為指數位置的數。由此,我們同樣的利用了分治思想,將指數分成了2的n次方和的形式。配合上右移運算,我們只要將其二進制數與1做與運算,為真則將此位上的2^n次方加入,為假則不加入。下面放出代碼:
?
以上便是全部內容,第一次發文,多有錯誤。多多包含。
?
學習本塊知識參考過的博文:
http://blog.csdn.net/zhizichina/article/details/7573342
http://blog.csdn.net/hkdgjqr/article/details/5381028
關于快速求冪的ACM題集:
HDU1575、HDU1852、HDU2817、HDU2035.
?
轉載于:https://www.cnblogs.com/Destiny-Gem/p/qpow.html
總結
以上是生活随笔為你收集整理的快速求幂(Quick Exponentiation)的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: CSS选择器详解(一)常用选择器
- 下一篇: Day5:面向对象的定义(中)