1. 程式人生 > >Pollard_Rho 整數分解法【學習筆記】

Pollard_Rho 整數分解法【學習筆記】

size 質數 else pac 優先級 篩選 one http fst

引文:如果要對比較大的整數分解,顯然之前所學的篩選法和是試除法都將不再適用。所以我們需要學習速度更快的Pollard_Rho算法。

算法原理:

生成兩個整數ab,計算p=gcd(a-b, n),知道p不為1a,b出現循環為止,若p=n,則n為質數,否則pn的一個約數。

對於如何生成這兩個數,選取一個小的隨機數x1,叠代生成

技術分享圖片

通過這個方式,我們只需要知道x1和c就可以生成一系列數值,c可以取任意給定值,一般取c=1。

若序列出現循環,則退出。

計算p=gcd(xi-1-xi, n), 若p=1,返回上一步,直到p>1為止;若p=n,則n為素數,否則p為一個約數並遞歸分解pn/p

例題:

https://vjudge.net/problem/POJ-1811

代碼:

技術分享圖片
  1 #include <iostream>
  2 #include <cstdio>
  3 #include <fstream>
  4 #include <vector>
  5 #include <queue>
  6 #include <algorithm>
  7 #include <map>
  8 #include <cmath>
  9 
 10 using namespace std;
 11 typedef long
long LL; 12 const int Test[] = {2, 3, 5, 7, 11, 13, 17, 19}; 13 const int Times = 8; 14 vector<LL> Factor; 15 16 LL gcd(LL a, LL b) 17 { 18 return b==0?a:gcd(b, a%b); 19 } 20 21 LL Multi(LL a, LL b, LL mod) 22 { 23 LL ans = 0; 24 while(b) 25 { 26 if(b&1
) 27 ans = (ans + a)%mod; 28 a = (a+a)%mod; 29 b>>=1; 30 } 31 return ans; 32 } 33 34 LL Pow(LL a, LL b, LL mod) 35 { 36 LL ans = 1; 37 while(b) 38 { 39 if(b&1) 40 { 41 ans = Multi(ans, a, mod); 42 } 43 b>>=1; 44 a=Multi(a, a, mod); 45 } 46 return ans; 47 } 48 49 bool Miller_Rabin(LL n) 50 { 51 if(n < 2) return false; 52 LL s = n-1, t = 0, x, next; 53 while(!(s&1) ) //根據運算符的優先級必須加括號 54 { 55 s>>=1; 56 t++; 57 } 58 for(int i = 0; i < Times; i++) 59 { 60 if(n== Test[i]) return true; 61 x = Pow(Test[i], s, n); 62 for(int j = 1; j <= t; j++) 63 { 64 next = Multi(x, x, n); 65 if(next == 1 && x != 1 && x != n-1) 66 return false; 67 x = next; 68 } 69 if(x != 1) 70 return false; 71 } 72 return true; 73 } 74 75 LL Pollard_Rho(LL n, int c) 76 { 77 LL i = 1, k = 2; 78 LL x = rand()%(n-1) + 1, y; //保證隨機數在(0,n)內 79 y = x; 80 while(1) 81 { 82 i++; 83 x = (Multi(x, x, n) + c)%n; //繼續生成數 84 LL p = gcd(x>y?x-y:y-x, n); 85 if(p!=1 && p!=n) //因為p>1 86 return p; 87 if(y == x) 88 return n; 89 if(i == k) 90 { 91 y = x; 92 k<<=1; 93 } 94 } 95 } 96 97 void Find(LL n, int c) 98 { 99 if(n == 1) 100 return; 101 if(Miller_Rabin(n)) 102 { 103 Factor.push_back(n); 104 return; 105 } 106 LL p = n, k = c; 107 while(p >= n) 108 { 109 p = Pollard_Rho(n, c--); 110 } 111 Find(p, k); 112 Find(n/p, k); 113 } 114 115 116 int main() 117 { 118 int T; 119 LL x; 120 cin >>T; 121 while(T--) 122 { 123 Factor.clear(); 124 cin >> x; 125 Find(x, 107); //107足矣 126 if(Factor.size() == 1) 127 printf("Prime\n"); 128 else 129 { 130 sort(Factor.begin(), Factor.end()); 131 printf("%I64d\n", Factor[0]); 132 } 133 } 134 }
Code

Pollard_Rho 整數分解法【學習筆記】