poj 2262

sqrt里的参数需要注意类型否则编译错误

#include <iostream>

#include <stdio.h>
#include <cmath>


using namespace std;


int isPrime(int m)
{
    for(int i = 2;i <= sqrt((double)m);i++)
    {
        if(m % i == 0)
            return 0;
    }
    return 1;
}


int main()
{
    int n;
    while(scanf("%d",&n) == 1 && n != 0)
    {
        int a,flag = 0;
        for(a = 3;a <= n / 2;a += 2)
        {
            if(isPrime(n - a) && isPrime(a))
            {
                flag = 1;
                printf("%d = %d + %d\n",n,a,n - a);
                break;
            }
        }
        if(!flag)
            printf("Goldbach's conjecture is wrong.\n");
    }
    return 0;

}


//筛法的自己实现

int num[1000000];


//0素1合
void getPrime()
{
    memset(num,0,sizeof(num));
    num[0] = 1;
    num[1] = 1;
    for(int i = 2;i < 1000000;i++)
    {
        int tmp;
        if(!num[i])
        {
            tmp = i + i;
            while(tmp < 1000000)
            {
                num[tmp] = 1;
                tmp += i;
            }
        }
    }
}


int isPrime(int m)
{
    return num[m] == 0;
}


poj 2262 Goldbach's Conjecture(素数判定)  

2009-11-12 09:41:02|  分类: POJ题解|字号 订阅

//考查点:判断素数的方法。

//思路:此题要求输入一个大于4的数, 输出表述成两个素数的和,我用 scanf 和 printf。

//提交情况: Compile Error了几次,主要是用j = sqrt(num)时选了C++编译器,用GCC一次就AC
                            
         
//收获:学到了判断素数的基本用法

//经验: 写好代码后本地编译而且需要静态观察,杜绝编译错误。

// 求出所有素数的方法
思路:以空间换时间,利用筛选法求素数。  4076K            157MS

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25

1倍不算

遍历一遍,“删掉”(标记)2的倍数:得2 3 5 7 9 11 13 15 17 19 21 23 25 (4,6,8的倍数就是2的倍数)

遍历一遍,删掉3的倍数:得2 3 5 7 11 13 17 19 23 25(6, 9, 12的倍数就是3的倍数)

遍历一遍,删掉5的倍数:得2 3 5 7 11 13 17 19 23(10, 15, 25的倍数就是5的倍数)

为了减小判断,加入if判断

#include <stdio.h>
#define MAX 1000001

int prime[MAX] = { 0};  // 0为素数,1不是素数

void getprime()
{
     int i, j;
     for (i =  2; i < MAX/ 2; i++)
    {
         if (!prime[i])  // 加上判断减少时间
        {
             for (j =  2; i*j < MAX; j++)
            {
                prime[j*i] =  1// 是某一个数的倍数        
            }
        }
    }
    prime[ 0] = prime[ 1] =  1

}

int main()
{
     int n, i, has;
    
    getprime();
    has =  0;
     while (scanf( "%d", &n)== 1 && n !=  0) {
         for (i =  3; i <= n/ 2; i +=  2) {  // 只有奇数才可能是素数
             if (prime[i] ==  1 || prime[n-i] ==  1)
            {
                 continue;
            }  else {
                printf( "%d = %d + %d \n ", n, i, n-i);
                 break;
            }
        }
         if (i > n/ 2)
            printf( "Goldbach's conjecture is wrong. \n ");
    }
        
     return  0;
}


// AC Co de
 1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
#include <stdio.h>
#include <math.h>

int isprime(int num)
{
int i, j;
j = sqrt(num);
for (i = 2; i <= j; i++)
if (num%i == 0)
return 0;
return 1;
}

int main()
{
int n, i, has;

has = 0;
while (scanf("%d", &n)==1 && n != 0) {
for (i = 2; i <= n/2; i++) {
if (isprime(i) && isprime(n-i)) {
has = 1;
printf("%d = %d + %d\n", n, i, n-i);
break;
}
}
if (!has)
printf("Goldbach's conjecture is wrong.\n");
}
return 0;
}

另附判断素数的方法:
判断n是否为素数

1、最简单的方法
用n除以2-sqrt(n),有一个能除尽就不是素数,否则是素数。
时间复杂度:O(sqrt(n))

2、素数判断法:
这种方法是对上面方法的改进,上面方法是对2-sqrt(n)之间的数进行判断是否能除尽,而因为有如下算术基本定理,可以减少判断量。
算术基本定理:又称为素数的唯一分解定理,即:每个大于1的自然数均可写为素数的积,而且这些素因子按大小排列之后,写法仅有一种方式。例如:6936 = 2^3×3×17^2,1200 = 2^4×3×5^2。
由算术基本定理知,任何合数都可分解为一些素数的乘积,所以判断一个数能不能被2-sqrt(n)之间的素数整除即可。但是必须知道2-sqrt(n)之间的所有素数。

3、筛选法
这种方法可以找出一定范围内的所有的素数。
思路是,要求10000以内的所有素数,把1-10000这些数都列出来,1不是素数,划掉;2是素数,所有2的倍数都不是素数,划掉;取出下一个幸存的数,划掉它的所有倍数;直到所有幸存的数的倍数都被坏掉为止。

要找出10000以为的所有的素数,则需要一个大小为10000的数组,将其所有元素设置为未标记
首先把1设置为标记,从2开始,标记所有是它倍数的数,然后对下一个没有标记的数进行标记它的倍数。
当标记完成后,所有未标记的数即为素数。
这种算法需要O(n)的空间,不要偶数,可以节省一半的存储空间,标记需要O(n^2/logn)(我写的,不知道对不对),判断是否是素数只需要O(1)的时间。


贴一下程序代码:

/*
    2009.5.12 by HK
*/
#include <stdio.h>
#include <math.h>
#include <string.h>

int  a [ 10000 ];

//100以内的素数
int  prime100 []  = 
{
     2 ,  3 ,  5 ,  7 ,  11 ,  13 ,  17 ,  19 ,  23 ,  29 ,  31 ,  37 ,  41 ,  43 ,  47 ,  53 ,  59 ,  61 ,  67 ,  71 ,  73 ,  79 ,  83 ,  89 ,  97 ,
};

/************************************************************************/
/*    第一种方法:最简单的方法                                            */
/************************************************************************/

int  is_prime1( int n)
{
     if(n  %  2  ==  0)
         return  0;

     for( int  i = 3; i <= sqrt(( double)n); i += 2)
         if(n  %  i  ==  0)
             return  0;

     return  1;
}

/************************************************************************/
/*    第二种方法:素数判断法                                              */
/*    若判断10000以内的数,需要知道100以内的所有素数                        */
/************************************************************************/

int  is_prime2( int n)
{
     int  i;
     for( i = 0; i < 25; i ++)
         if(n  %  prime100 [ i ]  ==  0)
             return  0;
     return  1;
}


/************************************************************************/
/*    第三种方法:筛选法,打素数表,然后判断                                */
/************************************************************************/

//筛选,a[i]=0,i为素数
void  create_table()
{
     int  i ,  tmp;
     memset( a ,  0 ,  sizeof( a));
     a [ 0 ]  =  1;
     a [ 1 ]  =  1;
     for( i = 2; i < 10000; i ++)
     {
         if( ! a [ i ])
         {
             tmp  =  i * 2;;
             while( tmp  <  10000)
             {
                 a [ tmp ]  =  1;
                 tmp  +=  i;
             }
         }
     }
}

int  is_prime3( int n)
{
     return  ! a [n ];
}



int  main()
{
     int  num ,  res;
     create_table();
     printf( "Input the num:");
     scanf( "%d" ,  & num);
     res  =  is_prime3( num);
     if( res)
         printf( "%d is a prime \n " ,  num);
     else
     printf( "%d is not a prime \n " ,  num);
     return  0;
}


                                                                判断素数的四种方法

/*求素数的三种方法 
一:for(i=2;i<=(n-1);i++) 
if(n%i==0)i在2到n-1之间任取一个数,如果n能被整除则不是素数,否则就是素数 
二:for(i=2;i<n/2;i++) 
if(n%i==0) /*i在2到n/2之间任取一个数,如果n能被整除则不是素数,否则就是素数 

三:for(i=2;i<(n=sqrt(n));i++) 
if(n%i==0) /*i在2到sqrt(n)之间任取一个数,如果n能被整除则不是素数,否则就是素数,

四、追求速度的一种方法(用素数表)

算术基本定理(素数唯一分解定理)任何一大于1的整数均可以分解为素数的乘积,若不考虑素数乘积的先后顺序,则分解式是唯一的。换句话说, 任意正整数n可以写成n=2a1*3a2*5a3*…,其中a1,a2,a3等为非负整数。

新方法的思路其实不新,只是利用了一个小技巧:一个正整数如果不能被所有不大于它的平方根的素数整除,则它一定是素数。我在判断正整数i是否为素数时,不是让它去整除每一个不大于它的平方根的正整数,而是让它去整除已经得到的素数表中的素数(此时素数表中的素数比i要小的多),这样就大大地减少了运算量。
      如果需要求超大的素数,int64 的有20位,甚至高精度情况下的素数,百位上千位可以建立素数表来求 ,所以,对于每个我们需要判断的数,只需要用素数表里的数来除即可,若都不能整除,那此数一定也是素数,那就把它加入素数表内,一直求下去就行,一般来说 10000个数的素数表就能判断int32内的素数,素数表能判断素数的范围是表内最大那个素数的平方。

     证明:for j=2 to 表内最大的那个素数(通常这里写sqrt(x)),所以最大可以算到表内最大的那个素数的平方。


转载 【转载】几种常见的素数判断算法te>收藏te>

求解一个算法,我们首先要知道它的数学含义.依据这个原则,首先我们要知道什么是素数.; 素数是这样的整数,它除了表示为它自己和1的乘积以外,无论他表示为任何两个整数的乘积。

找素数的方法多种多样。

1:是从2开始用“是则留下,不是则去掉”的方法把所有的数列出来(一直列到你不想再往下列为止,比方说,一直列到10,000)。第一个数是2, 它是一个素数,所以应当把它留下来,然后继续往下数,每隔一个数删去一个数,这样就能把所有能被2整除、因而不是素数的数都去掉。在留下的最小的数当中, 排在2后面的是3,这是第二个素数,因此应该把它留下,然后从它开始往后数,每隔两个数删去一个,这样就能把所有能被3整除的数全都去掉。下一个未去掉的 数是5,然后往后每隔4个数删去一个,以除去所有能被5整除的数。再下一个数是7,往后每隔6个数删去一个;再下一个数是11,往后每隔10个数删一个; 再下一个是13,往后每隔12个数删一个。就这样依法做下去。

但是编程我们一般不采用上面的方法,并不说这中方法计算机实现不了,或者说实现算法比较复杂。因为它更像一个数学推理。最后我们也给一个算法。

下面我们介绍几种长用的编程方法。

       2:遍历2以上N的平方根以下的每一个整数,是不是能整除N;(这是最基本的方法)

       3:遍历2以上N的平方根以下的每一个素数,是不是能整除N;(这个方法是上面方法的改进,但要求N平方根以下的素数已全部知道)
       4:采用Rabin-Miller算法进行验算;

例如:N=2^127-1是一个38位数,要验证它是否为素数,用上面几个不同的方法:

验算结果,假设计算机能每秒钟计算1亿次除法,那么
算法2要用4136年,算法3要用93年,算法4只要不到1秒钟!(这些数据是通过计算得到)

另外印度有人宣称素数测试是P问题,我一直没有找到那篇论文,听说里面有很多数学理论。如果那位大人有这篇论文,麻烦转发一份。 

下面我们分别实现上面的三种算法:

以下算法我们不涉及内存溢出,以及大数字的问题。如果测试数字超过2^32,发生内存溢出,你需要自己使用策略解决这个问题,在这里只讨论32位机有效数字算法。

1:// 算法0:是从2开始用“是则留下,不是则去掉”的方法把所有的数列出来

// 最后数组中不为0的数字就是要查找的素数。

void PrimeNumber0()

{

     //   int time ::GetTickCount();

     //   cout << "start time:" << time << endl;

     int Max[MAX_NUMBER];        // 在栈上分配,栈上空间要求一般都在2M之间,

     //   如果你需要更大空间,请在堆上申请空间(就是通过malloc,new来申请).

     memset(Max,0,MAX_NUMBER);

     for(int i = 0 ;  i < MAX_NUMBER; ++i)

     {

         Max[i] = i;

     }

     int cout = 0;// 记录当前i的位置

     // 遍历整个数组

     for(i = 1; i < MAX_NUMBER; ++i)

     {

         if(Max[i] != 0 )// 如果数据不为0,说明是一个素数

         {

              int iCout = i;

              int j = Max[i];// 记录数组中数组位的数字,以便设置

              while((iCout+=j) < MAX_NUMBER)

              {

                   // 把不是素数的数位在数组中置为0

                   Max[iCout] = 0;

              }

              ++cout;

         }

     }

     //   int time ::GetTickCount();

     //   cout << "end time:" << time << endl;

}

2:这个算法可以修改成为,验证一个给定数字是否是一个素数。

// 因为我们讨论多个算法,所以我们把每个算法都单独

// 写在一个或多个函数内。这些函数并不要求输入值和返回值

// 如果你需要这些结果,可以自己修改。

// 算法1:遍历2以上N的平方根以下的每一个整数,是不是能整除N;

void PrimeNumber1()

{

//   int time ::GetTickCount();

//   cout << "start time:" << time << endl;

     int Max[MAX_NUMBER/2];      // 在栈上分配,栈上空间要求一般都在2M之间,

//   如果你需要更大空间,请在堆上申请空间(就是通过malloc,new来申请).素数的个数很少

// 所以没有必要申请和所求数字同样大小的空间。

     memset(Max,0,MAX_NUMBER);

     Max[0] = 2;// 放入第一个素数,有人说2不是素数,如果你是其中一员,就改成3吧

     int cout = 1;// 记录素数个数

     // 挨个数进行验证

     bool bflag = true;

     for(int i = 3; i < MAX_NUMBER; ++i)

     {

         bflag = true;

         // 需要是使用数学库(math.h)中sqrt

         int iTemp = (int)sqrt((float)i);// 强制转换成int类型,有的人在这里使用i+1就是为了增加sqrt的精度

         // 没有特殊函数,你也可以使用int iTemp = (int)sqrt(i)+1;来提高进度

         for (int j = 2; j < iTemp; ++j)

         {

              if(i%j == 0)// 求余,如果为0说明,可以整除,不是素数。

              {

                   bflag = false;

                   break;

              }

         }

         // 经过验证是素数,放入数组。

         if(bflag)

         {

              Max[cout++] = i;

         }

     }

//   int time ::GetTickCount();

//   cout << "end time:" << time << endl;

}

3:这个方法是上面方法的改进,但要求N平方根以下的素数已全部知道

// 算法2:遍历2以上N的平方根以下的每一个素数,是不是能整除N;

// (这个方法是上面方法的改进,但要求N平方根以下的素数已全部知道)

void PrimeNumber2()

{

     //   int time ::GetTickCount();

     //   cout << "start time:" << time << endl;

     int Max[MAX_NUMBER/2];      // 在栈上分配,栈上空间要求一般都在2M之间,

     //   如果你需要更大空间,请在堆上申请空间(就是通过malloc,new来申请).素数的个数很少

     // 所以没有必要申请和所求数字同样大小的空间。

     memset(Max,0,MAX_NUMBER);

     Max[0] = 2;// 放入第一个素数,有人说2不是素数,如果你是其中一员,就改成3吧

     int cout = 1;// 记录素数个数

     // 挨个数进行验证

     bool bflag = true;

     for(int i = 3; i < MAX_NUMBER; ++i)

     {

         bflag = true;

         // 需要是使用数学库(math.h)中sqrt

         int iTemp = (int)sqrt((float)i);// 强制转换成int类型,有的人在这里使用i+1就是为了增加sqrt的精度

         // 没有特殊函数,你也可以使用int iTemp = (int)sqrt(i)+1;来提高进度

/

         // 修改的是这里以下的部分

         for (int j = 0; j < cout; ++j)

         {

              if(i%Max[j] == 0)// 求余,如果为0说明,可以整除,不是素数。

              {

                   bflag = false;

                   break;

              }

         }

         // 修改的是这里以上的部分

//

         // 经过验证是素数,放入数组。

         if(bflag)

         {

              Max[cout++] = i;

         }

     }

     //   int time ::GetTickCount();

     //   cout << "end time:" << time << endl;

}

4:采用Rabin-Miller算法进行验算,Rabin-Miller算法是典型的验证一个数字是否为素数的方法。判断素数的方法是 Rabin-Miller概率测试,那么他具体的流程是什么呢。假设我们要判断n是不是素数,首先我们必须保证n 是个奇数,那么我们就可以把n 表示为 n = (2^r)*s+1,注意s 也必须是一个奇数。然后我们就要选择一个随机的整数a (1<=a<=n-1),接下来我们就是要判断 a^s=1 (mod n) 或a^((2^j)*s)= -1(mod n)(0<=j如果任意一式成立,我们就说n通过了测试,但是有可能不是素数也能通过测试。所以我们通常要做多次这样的测试,以确保我们得到的是一 个素数。(DDS的标准是要经过50次测试)

// 算法3:采用Rabin-Miller算法进行验算

//首先选择一个代测的随机数p,计算b,b是2整除p-1的次数。然后计算m,使得n=1+(2^b)m。

//(1) 选择一个小于p的随机数a。

//(2) 设j=0且z=a^m mod p

//(3) 如果z=1或z=p-1,那麽p通过测试,可能使素数

//(4) 如果j>0且z=1, 那麽p不是素数

//(5) 设j=j+1。如果j且z<>p-1,设z=z^2 mod p,然后回到(4)。如果z=p-1,那麽p通过测试,可能为素数。

//(6) 如果j=b 且z<>p-1,不是素数

// 判定是否存在 a^s=1 (mod n) 或a^((2^j)*s)= -1(mod n)(0<=j

bool Witness(int a,int n)

{

     // 解释一下数学词汇:

     // ceil求不小于x的最小整数,函数原型extern float ceil(float x);求得i的最大值

     // log计算x的自然对数,函数原型extern float log(float x);

     long i,d=1,x;

     for (i=(int)ceil(log((double)n-1)/log(2.0))-1;i>=0;--i)

     {

         x=d;

         d=(d*d)%n;

         if ((1==d) && (x!=1) && (x!=n-1))

         {

              return 1;

         }

         if ((n-1)&(1<0))

         {

              d=(d*a)%n;

         }

     }

     return (d!=1);

}

// 参数n,是要测定的数字,s是要内部测试的次数。

bool Rabin_Miller(int n,int s)

{

     for (int j = 0;j < s; ++j)

     {

         int a = rand()*(n-2)/RAND_MAX + 1;// 获得一个随机数1<=a<=n-1

         if (Witness(a,n))// 利用这个随即数和n进行判断对比,只要有一次返回true,就说明n不是一个素数

         {

              return false;

         }

     }

     return true;// 通过验证是一个素数

}

// 算法3:采用Rabin-Miller算法进行验算

// 这个算法是求大素数使用的。所以你的必须想办法支持大数字运算,

// 不然极易造成内存访问失效,我在我的机子上,MAX_NUMBER=10000时就会出现问题,1000就没有问题

void PrimeNumber3()

{

    

     int Max[MAX_NUMBER/2];// 在栈上分配,栈上空间要求一般都在2M之间,

     //   如果你需要更大空间,请在堆上申请空间(就是通过malloc,new来申请).素数的个数很少

     // 所以没有必要申请和所求数字同样大小的空间。

     int cout = 0;// 记录素数个数

     memset(Max,0,MAX_NUMBER/2);

     for(int i = 2; i < 1000; ++i)

     {

         if(Rabin_Miller(i,20))

         {

              Max[cout++] = i;

         }

     }

}

以上程序都经过测试,测试环境Window 2003+VC7.1

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值