0048算法笔记——【随机化算法】拉斯维加斯随机化算法求解整数因子分解中的因子分割问题

      问题描述

     设n>1是一个整数。关于整数n的因子分解问题是找出n的如下形式的唯一分解式:其中,p1<p2<…<pk是k个素数,m1,m2,…,mk是k个正整数。如果n是一个合数,则n必有一个非平凡因子x,1<x<n,使得x可以整除n。给定一个合数n,求n的一个非平凡因子的问题称为整数n的因子分割问题

    求解思路

     整数因子分解最直观的方法当数“试除法”,数论中的Mertens定理告诉我们76%的奇数都有小于100的素因子,因此对于大多数整数,“试除法”已经足够,但是对于特殊的数,特别是素因子普遍较大的时候,“试除法"的效率便明显不足。和素数检验类似,目前几乎所有实用的分解方法都是概率性的算法, 目标是找到能计算x 的算法, 使得(x,N) > 1 的概率较大(而最大公因子可以很快地计算).      

    试除法因子分割如下:

  1. int Split(int n)  
  2. {  
  3.     int m = floor(sqrt(double(n)));  
  4.     for (int i=2; i<=m; i++)  
  5.     {  
  6.         if (n%i==0)  
  7.         {  
  8.             return i;  
  9.         }  
  10.     }  
  11.     return 1;  
  12. }  
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;
}
     算法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,以及2^k<j<=2^(k+1),算法计算出xj-xi与n的最大公因子d=gcd(xj-xi,n)。如果d是n的非平凡因子,则实现对n的一次分割,算法输出n的因子d。

     算法具体实现如下:

     1、RandomNumber.h

  1. #include"time.h"   
  2. //随机数类   
  3. const unsigned long maxshort = 65536L;  
  4. const unsigned long multiplier = 1194211693L;  
  5. const unsigned long adder = 12345L;  
  6.   
  7. class RandomNumber  
  8. {  
  9.     private:  
  10.         //当前种子   
  11.         unsigned long randSeed;  
  12.     public:  
  13.         RandomNumber(unsigned long s = 0);//构造函数,默认值0表示由系统自动产生种子   
  14.         unsigned short Random(unsigned long n);//产生0:n-1之间的随机整数   
  15.         double fRandom(void);//产生[0,1)之间的随机实数   
  16. };  
  17.   
  18. RandomNumber::RandomNumber(unsigned long s)//产生种子   
  19. {  
  20.     if(s == 0)  
  21.     {  
  22.         randSeed = time(0);//用系统时间产生种子   
  23.     }  
  24.     else  
  25.     {  
  26.         randSeed = s;//由用户提供种子   
  27.     }  
  28. }  
  29.   
  30. unsigned short RandomNumber::Random(unsigned long n)//产生0:n-1之间的随机整数   
  31. {  
  32.     randSeed = multiplier * randSeed + adder;//线性同余式   
  33.     return (unsigned short)((randSeed>>16)%n);  
  34. }  
  35.   
  36. double RandomNumber::fRandom(void)//产生[0,1)之间的随机实数   
  37. {  
  38.     return Random(maxshort)/double(maxshort);  
  39. }  
#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);
}
     2、7d4d2.cpp

  1. //随机化算法 拉斯维加斯算法 因子分割问题   
  2. #include "stdafx.h"   
  3. #include "RandomNumber.h"   
  4. #include <iostream>   
  5. using namespace std;  
  6.   
  7. //求整数a和b最大公因数的欧几里得算法   
  8. int gcd(int a,int b)  
  9. {  
  10.     if(b==0)  
  11.     {  
  12.         return a;  
  13.     }  
  14.     else  
  15.     {  
  16.         return gcd(b,a%b);  
  17.     }  
  18. }  
  19.   
  20. //求整数n因子分割的拉斯维加斯算法   
  21. void Pollard(int n)  
  22. {  
  23.     RandomNumber rnd;  
  24.     int i = 1;  
  25.     int x = rnd.Random(n);          //随机整数   
  26.     int y = x;  
  27.     int k = 2;  
  28.   
  29.     while(true)  
  30.     {  
  31.         i++;  
  32.         x = (x*x - 1) % n;          //x[i]=(x[i-1]^2-1) mod n   
  33.         int d = gcd(y-x,n);         //求n的非平凡因子   
  34.   
  35.         if((d>1) && (d<n))  
  36.         {  
  37.             cout<<d<<endl;//因子分割问题:求n的[一]个非平凡因子的问题   
  38.             return;  
  39.         }  
  40.   
  41.         if(i == k)  
  42.         {  
  43.             y = x;  
  44.             k *= 2;  
  45.         }  
  46.     }  
  47. }  
  48.   
  49. int main()  
  50. {  
  51.     int n = 1024;  
  52.     cout<<n<<"的非平凡因子:"<<endl;  
  53.     Pollard(n);  
  54.     return 0;  
  55. }  
//随机化算法 拉斯维加斯算法 因子分割问题
#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;
}
     对Pollard算法更深入的分析可知,执行算法的while循环约次后,Pollard算法会输出n的一个因子p。由于n的最小素因子,故Pollard算法可在O(n^(1/4))时间内找到n的一个素因子。

     程序运行结果如图:



  • 1
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值