分治法的經典問題——大整數相乘


分治法的原理

討論問題時,先來了解一下什么是分治法。

分治法的意思就是,分而治之,也就是把一個問題,拆分成幾個小問題,最后再匯總解決的方法

這里寫圖片描述

通過大整數相乘問題來了解分治法

假如現在我們要求兩個大整數相乘的乘積,如1234 * 1234(這里為了了分析簡便,所以不舉形如1234567891234567這樣的大整數,不必要在此糾結),那么按照我們小學學的乘法,就是用乘數的每一項去和1234相乘,這樣很明顯,算法的時間復雜度是O(n^2),效率很低下,那么有沒有一種更好的方式?我們可以使用分治法來解決。

這里寫圖片描述

算法分析

  1. 首先將X和Y分成A,B,C,D
  2. 此時將X和Y的乘積轉化為圖中的式子,把問題轉化為求解式子的值

看起來好像有點變化,分析一下:對這個式子,我們一共要進行4次 n / 2的乘法(AC2次, AD, BC)和 3次加法,因而該算法的時間復雜度為:

T(n) = 4 * T(n / 2) + θ(n) 
通過master定理可以求得 T(n) = θ(n ^ 2),跟小學算法的時間復雜度沒有區別。

但是我們再來看看,我們是否可以用加法來換取乘法?因為多一個加法操作,也是常數項,對時間復雜度沒有影響,如果減少一個乘法則不同。

XY=AC2^n+[(A-B)(D-C)+AC+BD]2^n/2+BD

現在的時間復雜度為:

T(n) = 3 * T(n / 2) + θ(n),通過master定理求得,T(n) = O(n^log2(3) ) = O(n^1.59 )。

Master定理:

這里寫圖片描述

Master定理實例: 
這里寫圖片描述

時間復雜度O的意義

這里寫圖片描述

實例分析

對X = 1234 和 Y = 5678來分析:

divideConquer(1234, 5678, 4) 
———————————————————————— 
X=1234 | A=12 | B=34 | A-B=-22

Y=5678 | C=56 | D=78 | D-C=22

三次遞歸: 
AC = divideConquer(12, 56, 2) 
BD = divideConquer(34, 78, 2) 
(A-B)(D-C) = divideConquer(-22, 22, 2)

AC遞歸 
————————————————————————

X=12 | A1=1 | B1=2 | A1-B1=-1

Y=56 | C1=5 | D1=6 | D1-C1=1

A1*C1 = divideConquer(1, 5, 1) = 5 
B1*D1 = divideConquer(2, 6, 1) = 12 
(A1-B1) * (D1-C1) = divideConquer(-1, 1, 1) = -1;

所以AC遞歸求得的值為:5 * 10 ^ 2 + (-1 + 5 + 12)* 10 + 12 = 672

同理可得 BD = 2652 和 (A-B)(D-C) = -484

最終可得 X * Y = 7006652

代碼實現

#include<cstdio> #include<cmath> using namespace std; #define SIGN(A) ((A > 0) ? 1 : -1) int divideConquer(int X, int Y, int n){ int sign = SIGN(X) * SIGN(Y); int x = abs(X); int y = abs(Y); if(x == 0 || y == 0){ return 0; }else if(n == 1){ return sign * x * y; }else{ int A = (int) x / pow(10, (int)(n / 2)); int B = x - A * pow(10, n / 2); int C = (int) y / pow(10, (int)(n / 2)); int D = y - C * pow(10, n / 2); int AC = divideConquer(A, C, n / 2); int BD = divideConquer(B, D, n / 2); int ABDC = divideConquer((A - B), (D - C), n / 2) + AC + BD; return sign * (AC * pow(10 , n) + ABDC * pow(10, (int)(n / 2)) + BD); } } int main(){ int x, y, n; scanf("%d%d%d", &x, &y, &n); printf("x 和 y的乘積為:%d", divideConquer(x, y, n)); }

 

結果:

這里寫圖片描述


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM