1. 程式人生 > >分治法的經典問題——大整數相乘

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

分治法的原理

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

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

這裡寫圖片描述

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

假如現在我們要求兩個大整數相乘的乘積,如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));
}

結果:

這裡寫圖片描述

相關推薦

對於治法整數相乘程式碼以及思路

分治演算法步驟: 1. 分解,將要解決的問題劃分為若干個規模較小的同類問題 2. 求解,當子問題劃分的足夠小時,用較簡單的方法解決 3. 合併,按原問題的要求,將子問題的解逐層合併構成原始問題的解 對於大整數相乘 需要如下幾步: 如 1234 5678 首先進行分解:

治法實現整數乘法【C++語言】

如果實現傳統演算法中兩個n位整數相乘,第一個整數中的n個數字都要分別乘以第二個整數的n個數字,這樣就一共要做n*n次乘法。看上去設計一個乘法次數少於n*n的演算法是不可能的,但事實證明並非如此,可以使用分治的思想計算兩個大整數的相乘。 首先從僅有兩位數字的兩個數12和34考慮,12 = 1 *

治法優化整數乘法 C++實現

上大學演算法分析實驗課的內容.關於利用分治法大整數乘法.還沒有解決大整數的儲存方式,應該是要利用一維陣列來解決.所以目前只是5位數的運算沒有問題.程式不是很健全,但是演算法的核心部分應該是已經都在這裡了. VC++6.0下測試通過. #include <iostream

治法整數加法

#include<bits/stdc++.h> using namespace std; string add(string a,string b) { if(a.length()<=8 && b.length()<=8)

治法實現整數乘法

#include <iostream>  #include <sstream>  #include <string>  using namespace std;  //string型別轉換成int型別 int string_to_num(string k)//str

治法解決整數乘法

大整數乘法 最近學習了演算法設計與分析課程,留了一道大整數乘法的問題,使用了分治法思想,和我之前在學校演算法俱樂部時所寫的原理不太一樣。於是分享出來 #include "pch.h" //大整數乘法 #include<iostream> #incl

治法經典問題——整數相乘

分治法的原理 討論問題時,先來了解一下什麼是分治法。 分治法的意思就是,分而治之,也就是把一個問題,拆分成幾個小問題,最後再彙總解決的方法 通過大整數相乘問題來了解分治法 假如現在我們要求兩個大整數相乘的乘積,如1234 * 1234(這

治法——整數相乘

post mat stdio.h log clas pos tdi class temp #include <stdio.h>#include <string.h>#include <conio.h>#include <math.h

治法---整數相乘

題目:大數相乘,例如:a=423405293459和b=323452345234533相乘a*b。 這裡我們採用分治的思想: 1:將該問題分成b的每個數和a相乘。 2:將每個數和a相乘得到結果存入一個數組中,每個數對應一個數組。 3:合併每個陣列,相加。 #in

[Nowcoder] 整數相乘(拼多多筆試題)

pac push_back coder 大數 str1 位數 問題 str 例子 有兩個用字符串表示的非常大的大整數,算出他們的乘積,也是用字符串表示。不能用系統自帶的大整數類型。 輸入描述: 空格分隔的兩個字符串,代表輸入的兩個大整數 輸出描述: 輸入的乘積,用字符串表

整數相乘問題總結以及Java實現

語言 java 變換 hal () 以及 pow divide 優化 最近在跟coursera上斯坦福大學的算法專項課,其中開篇提到了兩個整數相乘的問題,其中最簡單的方法就是模擬我們小學的整數乘法,可想而知這不是比較好的算法,這門課可以說非常棒,帶領我們不斷探索更優的算法,

分治演算法:整數相乘 字串實現

由於網上大部分用分治演算法實現的大整數相乘程式,其輸入乘數竟然設定為int值,實現了分治思想,但實在不能稱其為大整數。本文實現了用字串儲存乘數,並且輸出正確結果。由於演算法未經過大量資料測試,可能還存在問題,歡迎指教討論,求輕踩。。。 演算法分析:https://www.cnblogs.com/

java程式計算兩個整數相乘

方法1 :用兩個字串儲存輸入的大整數,然後用第二個字串的每一位去乘第一個字串的數字值,最後將每次的結果錯位相加即可。時間複雜度高O(n^2) 方法2:將兩個大整數X,Y每次分割成兩半,第一個分割成AB,第二個分割成CD。所以最後結果XY=(A*10^n/2 +B)(C*10^m/2+D);進

整數相乘問題

看到一道經典的面試題目---大整數相乘問題,完完整整敲了一遍,並且在牛客網運行了一遍,AC過了。 所採用的的方法是進位的方法。 舉個例子: 用 789 × 956 ,通過計算我們很容易得到 754284 , 除了筆算或者口算的方法我們還可以用一種非常巧妙的方法來進行計算。 這個方法的

整數相乘------java實現

大數相乘演算法實現:(Java版,使用BigInteger)(含有大數的加、減、乘、除) package com.bigInteger; import java.io.BufferedReader; import java.io.IOException; import

分治演算法-整數相乘(JAVA實現)

 上大學演算法分析實驗課的內容.關於利用分治法大整數乘法.還沒有解決大整數的儲存方式,應該是要利用一維陣列來解決.所以目前只是5位數的運算沒有問題.程式健全  1/** *//** 2 * 大整數項乘 3 * @author Administrator 4 * 5 */ 6import java.io.B

python實現整數相乘---格子乘法

        以前做ACM的時候,許多人都通過 BigInteger 來實現大數乘法,讓我記憶猶新的事2012年的遼寧省賽在大連大學,第一道水題就是大整數乘法,那時還不會java。 大數乘法的實現是基於印度的格子乘法,使用這種方法,計算 m 位數乘以 n 位數只需要建立一

關於整數相乘

由於int範圍有限,對於大整數相乘必定不能直接用*符號,而是用char型陣列記錄,通過模擬乘法達到大整數相乘的效果, 假定a陣列長度為A,b陣列長度為B。求出來的大整數長度有三種可能, 1.A+B(最後一位無進位), 2.A+B+1(最後一位有進位), 3.0(數a或者數b

治法 整數乘法

學習演算法的時候,其中一道經典就是大整數乘法咯,感覺有點難理解,於是寫一篇部落格加深下理解。 大數相乘不可以直接得到答案,肯定會超出數的範圍,而解決大數相乘的辦法就是分治法:將大問題變成小問題,再變成簡單問題,最後進行合併。 例如:        

[演算法入門經典] 8.1.3 治法 求最連續和

int maxsum(int *A,int x,int y) //返回陣列在左比右開區間[x,y)中的最大連續和 { int i, m, v, L, R, max; if(y-x==1) return A[x]; //只有一個元素,直接返回 m=x+(