1. 程式人生 > 實用技巧 >拉斯維加斯隨機化演算法求解整數因子分解

拉斯維加斯隨機化演算法求解整數因子分解

問題描述

設n>1是一個整數。關於整數n的因子分解問題是找出n的如下形式的唯一分解式:。其中,p1<p2<…<pk是k個素數,m1,m2,…,mk是k個正整數。如果n是一個合數,則n必有一個非平凡因子x,1<x<n,使得x可以整除n。給定一個合數n,求n的一個非平凡因子的問題稱為整數n的因子分割問題。

下面演算法split(n)可以對整數因子分割:

int Split(int n)
{
    int m = floor(sqrt(double(n)));
    for (int i=2; i<=m; i++)
    {
        if
(n%i==0) { return i; } } return 1; }
View Code

演算法split(n)是對範圍在1~x的所有整數進行了試除而得到範圍在1~x^2的任一整數的因子分割。

Pollard p - 1 方法由Pollard 於1974 年提出,用來找到給定合數n的一個因子d。Pollard演算法用於Split(n)相同工作量就可以得到在1~x^4範圍內整數的因子分割。具體過程如下:在開始時選取0~n-1範圍內的隨機數,然後遞迴地由
產生無窮序列對於i=2^k,k=0,1,.....以及2^k<j<=2^(k+1),演算法計算出xj-xi與n的最大公因子d=gcd(xj-xi,n)。如果d是n的非平凡因子,則實現對n的一次分割,演算法輸出n的因子d。

演算法具體實現如下:其中gcd(a,b)是求兩個整數最大公因素的歐幾里得演算法。

//隨機化演算法 拉斯維加斯演算法 因子分割問題
#include "stdafx.h"
#include "RandomNumber.h"
#include <iostream>
using namespace std;
 
//求整數a和b最大公因數的歐幾里得演算法
int gcd(int a,int b)
{
    if(b==0)
    {
        return a;
    }
    else
    {
        return gcd(b,a%b);
    }
}
 
//求整數n因子分割的拉斯維加斯演算法 void Pollard(int n) { RandomNumber rnd; int i = 1; int x = rnd.Random(n); //隨機整數 int y = x; int k = 2; while(true) { i++; x = (x*x - 1) % n; //x[i]=(x[i-1]^2-1) mod n int d = gcd(y-x,n); //求n的非平凡因子 if((d>1) && (d<n)) { cout<<d<<endl;//因子分割問題:求n的[一]個非平凡因子的問題 return; } if(i == k) { y = x; k *= 2; } } } int main() { int n = 1024; cout<<n<<"的非平凡因子:"<<endl; Pollard(n); return 0; }
View Code
#include"time.h"
//隨機數類
const unsigned long maxshort = 65536L;
const unsigned long multiplier = 1194211693L;
const unsigned long adder = 12345L;
 
class RandomNumber
{
    private:
        //當前種子
        unsigned long randSeed;
    public:
        RandomNumber(unsigned long s = 0);//建構函式,預設值0表示由系統自動產生種子
        unsigned short Random(unsigned long n);//產生0:n-1之間的隨機整數
        double fRandom(void);//產生[0,1)之間的隨機實數
};
 
RandomNumber::RandomNumber(unsigned long s)//產生種子
{
    if(s == 0)
    {
        randSeed = time(0);//用系統時間產生種子
    }
    else
    {
        randSeed = s;//由使用者提供種子
    }
}
 
unsigned short RandomNumber::Random(unsigned long n)//產生0:n-1之間的隨機整數
{
    randSeed = multiplier * randSeed + adder;//線性同餘式
    return (unsigned short)((randSeed>>16)%n);
}
 
double RandomNumber::fRandom(void)//產生[0,1)之間的隨機實數
{
    return Random(maxshort)/double(maxshort);
}
View Code

執行結果:

對Pollard演算法更深入的分析可知,執行演算法的while迴圈約次後,Pollard演算法會輸出n的一個因子p。由於n的最小素因子,故Pollard演算法可在O(n^(1/4))時間內找到n的一個素因子。在上述Polllard演算法中還可將產生序列Xi的遞迴式改作

Xi=(Xi-1^2-c)mod n,其中,c是一個不等於0和2的整數。

參考文獻:王曉東《演算法設計與分析》第二版

https://blog.csdn.net/liufeng_king/article/details/9246821