Pollard_rho算法进行质因素分解
Pollard_rho算法进行质因素分解要依赖于Miller_Rabbin算法判断大素数,没有学过的可以看一下,也可以当成模板来用
讲一下Pollard_rho算法思想:
求n的质因子的基本过程是,先判断n是否为素数,如果不是则按照一个伪随机数生成过程来生成随机数序列,对于每个生成的随机数判断与n是否互质,如果互质则尝试下一个随机数。如果不互质则将其公因子记作p,递归求解p和n/p的因子。如果n是素数则直接返回n为其素因子。
Pollard rho算法的原理就是通过某种方法得到两个整数a和b,而待分解的大整数为n,计算p=gcd(a-b,n),直到p不为1,或者a,b出现循环为止。然后再判断p是否为n,如果p=n成立,那么返回n是一个质数,否则返回p是n的一个因子,那么我们又可以递归的计算Pollard(p)和Pollard(n/p),这样,我们就可以求出n的所有质因子。
具体操作中,我们通常使用函数x2=x1*x1+c来计算逐步迭代计算a和b的值,实践中,通常取c为1,即b=a*a+1,在下一次计算中,将b的值赋给a,再次使用上式来计算新的b的值,当a,b出现循环时,即可退出进行判断。
在实际计算中,a和b的值最终肯定一出现一个循环,而将这些值用光滑的曲线连接起来的话,可以近似的看成是一个ρ型的。
对于Pollard rho,它可以在O(sqrt(p))的时间复杂度内找到n的一个小因子p,可见效率还是可以的,但是对于一个因子很少、因子值很大的大整数n来说,Pollard rho算法的效率仍然不是很好
为啥要取两个随机数的差?
对于一个大整数n,我们取任意一个数使得是的质因数的几率很小,但如果取两个数以及
使得它们的差是n的因数的几率就提高了,如果取x1以及x2使得gcd(abs(x1-x2), n) > 1的概率就更高了,这就是Pollard-Rho算法的思想。(概率的增加是因为组合数增加了)
为啥要用到Miller_Rabbin算法判断大素数?
因为最后结果是n的所有质因子的乘积(这个乘积的形式只会有一种),那么肯定要判断某个数是不是素数,用Miller_Rabbin算法判断大素数判断的话要比普通方法快
代码:
1 #include<stdio.h> 2 #include<string.h> 3 #include<iostream> 4 #include<algorithm> 5 #include<queue> 6 #include<map> 7 #include<vector> 8 #include<math.h> 9 #define mem(a,x) memset(a,x,sizeof(a)) 10 using namespace std; 11 typedef long long LL; 12 const int maxn=50005; 13 const int mod=26; 14 const int INF=0x3f3f3f3f; 15 const int Times = 10; 16 const int N = 5500; 17 LL ct, cnt; 18 LL fac[N], num[N]; 19 LL gcd(LL a, LL b) //求两数最大公因子 20 { 21 return b? gcd(b, a % b) : a; 22 } 23 LL multi(LL a, LL b, LL m) //快速乘 24 { 25 LL ans = 0; 26 a %= m; 27 while(b) 28 { 29 if(b & 1) 30 { 31 ans = (ans + a) % m; 32 b--; 33 } 34 b >>= 1; 35 a = (a + a) % m; 36 } 37 return ans; 38 } 39 LL pow(LL a, LL b, LL m) //快速幂 40 { 41 LL ans = 1; 42 a %= m; 43 while(b) 44 { 45 if(b & 1) 46 { 47 ans = multi(ans, a, m); 48 b--; 49 } 50 b >>= 1; 51 a = multi(a, a, m); 52 } 53 return ans; 54 } 55 bool Miller_Rabin(LL n) //判断n是不是素数 56 { 57 if(n == 2) return true; 58 if(n < 2 || !(n & 1)) return false; 59 LL m = n - 1; 60 int k = 0; 61 while((m & 1) == 0) 62 { 63 k++; 64 m >>= 1; 65 } 66 for(int i=0; i<Times; i++) 67 { 68 LL a = rand() % (n - 1) + 1; 69 LL x = pow(a, m, n); 70 LL y = 0; 71 for(int j=0; j<k; j++) 72 { 73 y = multi(x, x, n); 74 if(y == 1 && x != 1 && x != n - 1) return false; 75 x = y; 76 } 77 if(y != 1) return false; 78 } 79 return true; 80 } 81 LL pollard_rho(LL n, LL c) //大整数分解 82 { 83 LL i = 1, k = 2; 84 LL x = rand() % (n - 1) + 1; 85 LL y = x; 86 while(true) 87 { 88 i++; 89 x = (multi(x, x, n) + c) % n; 90 LL d = gcd((y - x + n) % n, n); 91 if(1 < d && d < n) return d; 92 if(y == x) return n; 93 if(i == k) 94 { 95 y = x; 96 k <<= 1; 97 } 98 } 99 } 100 void find(LL n, int c) //递归查找大整数n的质因子 101 { 102 if(n == 1) return; 103 if(Miller_Rabin(n)) 104 { 105 fac[ct++] = n; 106 return ; 107 } 108 LL p = n; 109 LL k = c; 110 while(p >= n) p = pollard_rho(p, c--); 111 find(p, k); 112 find(n / p, k); 113 } 114 int main() 115 { 116 LL n; 117 while(cin>>n) 118 { 119 ct = 0; 120 find(n, 120); 121 sort(fac, fac + ct); 122 num[0] = 1; 123 int k = 1; 124 for(int i=1; i<ct; i++) 125 { 126 if(fac[i] == fac[i-1]) 127 ++num[k-1]; 128 else 129 { 130 num[k] = 1; 131 fac[k++] = fac[i]; 132 } 133 } 134 cnt = k; 135 for(int i=0; i<cnt; i++) 136 cout<<fac[i]<<"^"<<num[i]<<" "; 137 cout<<endl; 138 } 139 return 0; 140 }