Pollard-rho的質因數分解

思路:見參考文章(原理我是寫不粗來了)

代碼:

用到了快速冪米勒羅賓素性檢驗html

  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的因子,找到了就不斷除,除到不能除爲止,再找下一個因子。ios

爲何保證是素因子,從二開始,假設有二的因子,不斷地除直到沒有二就能保證二的倍數也沒有了。相似於素數篩的思想。算法

代碼:

 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/45459533dom

陶無語,Pollard Rho因子分解算法,https://www.cnblogs.com/dalt/p/8437119.html(講解原理的多一點,不過至因而否容易理解,嘿嘿)post

相關文章
相關標籤/搜索