Pollard-rho的质因数分解

思路:见参考文章(原理我是写不粗来了)

代码:

用到了快速幂米勒罗宾素性检验

  1 #include <iostream>
  2 #include <time.h>
  3 #include <map>
  4 using namespace std;
  5 long long an[] = {2,3,5,7,11,13,17,61};
  6 map<long long,int> mp;//存因数和对应出现次数
  7 int num = 0;
  8 long long Random(long long n)//生成0到n之间的整数
  9 {
 10     return (double) rand()/RAND_MAX*n+0.5;//(doubel)rand()/RAND_MAX生成0-1之间的浮点数
 11 }
 12 
 13 
 14 long long q_mod(long long a,long long n,long long p)//快速幂
 15 {
 16     a = a%p;
 17     //首先降a的规模
 18     long long sum = 1;//记录结果
 19     while(n)
 20     {
 21         if(n&1)
 22         {
 23             sum = (sum*a)%p;//n为奇数时单独拿出来乘
 24         }
 25         a = (a*a)%p;//合并a降n的规模
 26         n /= 2;
 27     }
 28     return sum;
 29 }
 30 
 31 
 32 long long q_mul(long long a,long long b,long long p)//大数模
 33 {
 34     long long sum = 0;
 35     while(b)
 36     {
 37         if(b&1)//如果b的二进制末尾是零
 38         {
 39             (sum += a)%=p;//a要加上取余
 40         }
 41         (a <<= 1)%=p;//不断把a乘2相当于提高位数
 42         b >>= 1;//把b右移
 43     }
 44     return sum;
 45 }
 46 
 47 
 48 //Miller-Rabin
 49 bool witness(long long a,long long n)
 50 {
 51     long long d = n-1;
 52     long long r = 0;
 53     while(d%2==0)
 54     {
 55         d/=2;
 56         r++;
 57     }//n-1分解成d*2^r,d为奇数
 58     long long x = q_mod(a,d,n);
 59     //cout << "d " << d << " r " << r << " x " << x << endl;
 60     if(x==1||x==n-1)//最终的余数是1或n-1则可能是素数
 61     {
 62         return true;
 63     }
 64     while(r--)
 65     {
 66         x = q_mul(x,x,n);
 67         if(x==n-1)//考虑开始在不断地往下余的过程
 68         {
 69             return true;//中间如果有一个余数是n-1说明中断了此过程,则可能是素数
 70         }
 71     }
 72     return false;//否则如果中间没有中断但最后是余数又不是n-1和1说明一定不是素数
 73 }
 74 bool miller_rabin(long long n)
 75 {
 76     const int times = 50;//试验次数
 77     if(n==2)
 78     {
 79         return true;
 80     }
 81     if(n<2||n%2==0)
 82     {
 83         return false;
 84     }
 85     for(int i = 0;i<times;i++)
 86     {
 87         long long a = Random(n-2)+1;//1到(n-1)
 88         //cout << a << endl;
 89         if(!witness(a,n))
 90         {
 91             return false;
 92         }
 93     }
 94     return true;
 95 }
 96 
 97 
 98 //求gcd
 99 long long gcd(long long a,long long b)
100 {
101     return b==0?a:gcd(b,a%b);
102 }
103 
104 //Pollard-rho
105 long long Pollard_rho(long long n,long long c)
106 {
107     //cout << "n "  << n << " c " << c << endl;
108     long long i = 1,k = 2;
109     long long x = Random(n-1)+1;
110     long long y = x;
111     while(true)
112     {
113         i++;
114         x = (q_mul(x,x,n)+c)%n;
115         long long d = gcd(y-x,n);
116         if(1<d&&d<n)
117         {
118             return d;
119         }
120         if(x==y)
121         {
122             return n;
123         }
124         if(i==k)
125         {
126             y = x;
127             k<<=1;
128         }
129     }
130 }
131 void find(long long n,long long c)
132 {
133     if(n==1)//找完了
134     {
135         return;
136     }
137     if(miller_rabin(n))//找到了质数
138     {
139         num++;
140         mp[n]++;
141         return;
142     }
143     long long p = n;
144     while(p>=n)//找p的因数
145     {
146         p = Pollard_rho(p,c--);//返回p的因数或1或本身
147     }
148     find(p,c);//递归地找p的因子
149     find(n/p,c);
150 }
151 int main()
152 {
153     long long n;
154     while(cin >> n)
155     {
156         num = 0;
157         mp.clear();
158         find(n,2137342);//随机选取的c
159         cout << n << " = ";
160         if(mp.empty())
161         {
162             cout << n << endl;
163         }
164         for(auto ite = mp.begin();ite!=mp.end();ite++)
165         {
166             cout << ite->first << "^" << ite->second;
167             auto i = ite;
168             if(++i!=mp.end()) //如果不是最后一个
169             {
170                 cout << "*";//输出乘号
171             }
172         }
173     }
174     return 0;
175 
176 }

其他分解质因数的方法:

朴素算法:枚举从2到n找n的因子,找到了就不断除,除到不能除为止,再找下一个因子。

为什么保证是素因子,从二开始,假设有二的因子,不断地除直到没有二就能保证二的倍数也没有了。类似于素数筛的思想。

代码:

 1 map<int,int> mp;
 2 void decom1(int n)
 3 {
 4     for(int i = 2;i<=n;i++)
 5     {
 6         while(n%i==0)
 7         {
 8             mp[i]++;
 9             n /= i;
10         }
11     }
12 }

参考文章:

StanleyClinton,大数因数分解Pollard_rho 算法详解,https://blog.csdn.net/maxichu/article/details/45459533

陶无语,Pollard Rho因子分解算法,https://www.cnblogs.com/dalt/p/8437119.html(讲解原理的多一点,不过至于是否容易理解,嘿嘿)

 

posted @ 2019-07-28 12:14  小张人  阅读(1058)  评论(0编辑  收藏  举报
分享到: