鱼C论坛

 找回密码
 立即注册
查看: 5072|回复: 19

[争议讨论] 算法-极品素数 --参与有奖

[复制链接]
发表于 2011-7-23 10:40:46 | 显示全部楼层 |阅读模式

马上注册,结交更多好友,享用更多功能^_^

您需要 登录 才可以下载或查看,没有账号?立即注册

x
本帖最后由 冬冬 于 2011-7-23 16:50 编辑

极品素数:如果一组素数从1开始编号,如果他的序号也是素数,那么这个素数就称极品素数。
例:
2、3、5、7、11、13、17、19......
1、2、3、4、 5、  6、 7、  8、  9......
那么3、5、11、17就为极品素数。。。
统计N以内的所有极品素数个数

2<=N<=100000
测试时间为2秒

输入输出实例:
输入:20
输出:4



参与回帖的代码,活动结束后公开

想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
发表于 2011-7-23 13:13:48 | 显示全部楼层
1.LZ题目出错了,9=3*3,所以9不是素数,所以9不是极品素数
2.贴我的代码
  1. #include<stdio.h>
  2. #define NUMS 100000
  3. #define SQRT_NUMS 316

  4. static int vec[NUMS+1];

  5. /*
  6. 筛法求素数
  7. (1)vec[i]==0则i为素数
  8. (1)vec中下标为偶数的肯定不是素数
  9. */
  10. void initTable();
  11. //计算极品素数的个数
  12. int count(int n);

  13. int main(){
  14.         int number;
  15.         initTable();
  16.         while(scanf("%d",&number)!=EOF){
  17.                 printf("%d\n",count(number));
  18.         }
  19. }

  20. void initTable(){
  21.         int i,j;
  22.         for(i=3;i<=SQRT_NUMS;++i){
  23.                 if(vec[i]==0){
  24.                         for(j=i*i;j<=NUMS;j+=2*i)
  25.                                 vec[j]=1;
  26.                 }
  27.         }
  28. }

  29. int count(int n){
  30.         //2是极品素数
  31.         int result = 1;
  32.         //第几个素数
  33.         int priNumber = 1;
  34.         int i;
  35.         if(n<2) return 0;
  36.         for(i=5;i<=n;i+=2){
  37.                 if(vec[i]==0) {
  38.                         ++priNumber;
  39.                         if( priNumber%2 && vec[priNumber] == 0 ){
  40.                                 result++;
  41.                         }
  42.                 }
  43.         }
  44.         return result;
  45. }
复制代码

评分

参与人数 1荣誉 +5 鱼币 +3 收起 理由
冬冬 + 5 + 3 呵呵,见识到了以空间换时间的做法

查看全部评分

想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
 楼主| 发表于 2011-7-23 16:49:17 | 显示全部楼层

你的initTable函数做法让我郁闷,这样筛选的素数表能解释一下吗? 用来统计极品素数结果是大部分正确的,刚才又看了看,结果出现了一点异常。当我输入1万时,结果与我的相差1。
这是我的代码,嘿嘿用的是迭代法。:lol
  1. #include <iostream>
  2. #include <cmath>
  3. using namespace std;
  4. bool super(int x);
  5. int count(int n);
  6. void print(int n);
  7. int main()
  8. {
  9.     int number;
  10.     cin>>number;
  11.     //print(number);
  12.     cout<<count(number)<<endl;
  13.     system("pause");
  14.     return 0;
  15. }bool super(int x)
  16. {
  17.      bool flag=true;
  18.      if(x<2)
  19.      {
  20.             return false;
  21.      }
  22.      if(x==2)
  23.              return true;
  24.      else
  25.      {
  26.          for(int i=2;i<=sqrt(x);i++)
  27.          {
  28.                  if(x%i==0)
  29.                  {
  30.                            flag=false;
  31.                            break;
  32.                  }
  33.          }
  34.      }
  35.      return flag;
  36. }
  37. int count(int n)
  38. {
  39.      int c=0;
  40.      int item=0;
  41.      int i;
  42.      for(i=2;i<=n;i++)
  43.      {
  44.         if(super(i))
  45.                     item++;
  46.             if( super(i) && super(item))
  47.             {
  48.                 c++;
  49.                // cout<<i<<endl;
  50.             }
  51.      }
  52.      return c;
  53. }void print(int n)
  54. {
  55.      for(int i=2;i<=n;i++)
  56.      {
  57.              if(super(i))
  58.                          cout<<i<<"\t";
  59.      }
  60.      cout<<endl;
  61. }

复制代码

想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
头像被屏蔽
发表于 2011-7-23 17:41:17 | 显示全部楼层
提示: 作者被禁止或删除 内容自动屏蔽
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
 楼主| 发表于 2011-7-23 19:18:00 | 显示全部楼层
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
发表于 2011-7-23 22:25:14 | 显示全部楼层
我的程序有问题,改2个地方:
(1)38行改为int priNumber = 2;因为我从5开始检测,5之前已经有2个素数2和3了。(这个影响了程序的正确性,改后结果和LZ的一样)
(2)26行改为 for(i=3;i<=SQRT_NUMS;i+=2),这样运行效率更高些。
筛法的说明,我从百度百科copy过来给大家看看
筛法,是求不超过自然数N(N>1)的所有质数的一种方法。据说是古希腊的埃拉托斯特尼(Eratosthenes,约公元前274~194年)发明的,又称埃拉托斯特尼筛法(sieve of Eratosthenes)。
具体做法是:先把N个自然数按次序排列起来。1不是质数,也不是合数,要划去。第二个数2是质数留下来,而把2后面所有能被2整除的数都划去。2后面第一个没划去的数是3,把3留下,再把3后面所有能被3整除的数都划去。3后面第一个没划去的数是5,把5留下,再把5后面所有能被5整除的数都划去。c这样一直做下去,就会把不超过N的全部合数都筛掉,留下的就是不超过N的全部质数。因为希腊人是把数写在涂腊的板上,每要划去一个数,就在上面记以小点,寻求质数的工作完毕后,这许多小点就像一个筛子,所以就把埃拉托斯特尼的方法叫做“埃拉托斯特尼筛法”,简称“筛法”。(另一种解释是当时的数写在纸草上,每要划去一个数,就把这个数挖去,寻求质数的工作完毕后,这许多小洞就像一个筛子。)

      在这个基本的筛法基础上,我作了一些改进。以求10000内的素数为例,只要先求出100内的所有素数,然后,以100内的这些素数为筛子,可以把10000内所有的非素数筛掉。
      证明:假设某个大于100小于10000的合数没被筛掉,把它分解质因数,这些质因数里最小的,一定大于100(否则该数就会被100内的素数筛掉),但大于100的两个质因数的乘积一定大于10000.与假设矛盾,证毕。
      根据这个推论,要把100000的合数筛掉,就要求出1~100000平方根(316.XX)的素数。这就是initTable中for(i=3;i<=SQRT_NUMS;++i)循环的含义。此外当你得到一个素数,即if(vec==0)的时候,说明1~i*i的合数都已经被筛掉了(见前面的证明)。所以从i*i往后筛就可以了。
      还有一个因素可以帮助提高程序效率,就是所有的偶数位置肯定不是素数(2我作了特殊处理),所以筛的时候,步长可以选2*i(选i为步长的话每2步肯定出现一个偶数,偶数就不会是素数)。同理外层for循环步长也可以为2.
最终修正好的程序如下:(原来出错的地方都被我注释掉了)
  1. #include<stdio.h>
  2. #define NUMS 100000
  3. #define SQRT_NUMS 316

  4. static int vec[NUMS+1];

  5. /*
  6. 筛法求素数
  7. (1)vec[i]==0则i为素数
  8. (1)vec中下标为偶数的肯定不是素数
  9. */
  10. void initTable();
  11. //计算极品素数的个数
  12. int count(int n);

  13. int main(){
  14.         int number;
  15.         initTable();
  16.         while(scanf("%d",&number)!=EOF){
  17.                 printf("%d\n",count(number));
  18.         }
  19. }

  20. void initTable(){
  21.         int i,j;
  22.         //for(i=3;i<=SQRT_NUMS;++i){
  23.                 for(i=3;i<=SQRT_NUMS;i+=2){
  24.                 if(vec[i]==0){
  25.                         for(j=i*i;j<=NUMS;j+=2*i)
  26.                                 vec[j]=1;
  27.                 }
  28.         }
  29. }

  30. int count(int n){
  31.         //2是极品素数
  32.         int result = 1;
  33.         //第几个素数
  34.         //int priNumber = 1;
  35.                 int priNumber = 2;
  36.         int i;
  37.         if(n<2) return 0;
  38.         for(i=5;i<=n;i+=2){
  39.                 if(vec[i]==0) {
  40.                         ++priNumber;
  41.                         if( priNumber%2 && vec[priNumber] == 0 ){
  42.                             result++;
  43.                         }
  44.                 }
  45.         }
  46.         return result;
  47. }
复制代码
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
 楼主| 发表于 2011-7-23 22:44:16 | 显示全部楼层
仰望天上的光 发表于 2011-7-23 22:25
我的程序有问题,改2个地方:
(1)38行改为int priNumber = 2;因为我从5开始检测,5之前已经有2个素数2和 ...



我一直纳闷的是,我给你的代码添加了一个PrintTable函数,打印了2 - 100之间的素数,如下图。但是这个表用来统计极品素数,结果确实对的

QQ截图20110723224150.jpg
  1. #include<stdio.h>

  2. #define NUMS 100000

  3. #define SQRT_NUMS 316
  4. static int vec[NUMS+1];
  5. /*

  6. 筛法求素数

  7. (1)vec[i]==0则i为素数

  8. (1)vec中下标为偶数的肯定不是素数

  9. */

  10. void initTable();

  11. //计算极品素数的个数

  12. int count(int n);

  13. void PrintTable()
  14. {
  15.      for(int i=2;i<=100;i++)
  16.      {
  17.              if(vec[i]==0)  
  18.                             printf("%d\t",i);
  19.      }
  20.      printf("\n");
  21. }
  22. int main(){

  23.         int number;

  24.         initTable();
  25.         PrintTable();

  26.         while(scanf("%d",&number)!=EOF){

  27.                 printf("%d\n",count(number));

  28.         }

  29. }
  30. void initTable(){

  31.         int i,j;

  32.         //for(i=3;i<=SQRT_NUMS;++i){

  33.                 for(i=3;i<=SQRT_NUMS;i+=2){

  34.                 if(vec[i]==0){

  35.                         for(j=i*i;j<=NUMS;j+=2*i)

  36.                                 vec[j]=1;

  37.                 }

  38.         }

  39. }
  40. int count(int n){

  41.         //2是极品素数

  42.         int result = 1;

  43.         //第几个素数

  44.         //int priNumber = 1;

  45.                 int priNumber = 2;

  46.         int i;

  47.         if(n<2) return 0;

  48.         for(i=5;i<=n;i+=2){

  49.                 if(vec[i]==0) {

  50.                         ++priNumber;

  51.                         if( priNumber%2 && vec[priNumber] == 0 ){

  52.                             result++;

  53.                         }

  54.                 }

  55.         }

  56.         return result;

  57. }

复制代码

想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
发表于 2011-7-23 22:49:03 | 显示全部楼层
原版initTable中的问题只影响效率,不影响结果。(即素数表的结果是正确的)
主要是count函数中的修改影响正确性。你并没有测试count函数

评分

参与人数 1鱼币 +1 收起 理由
冬冬 + 1 巧妙的设计,高效的算法

查看全部评分

想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
头像被屏蔽
发表于 2011-7-23 22:58:34 | 显示全部楼层
提示: 作者被禁止或删除 内容自动屏蔽
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
发表于 2011-7-24 00:29:40 | 显示全部楼层
本帖最后由 紫色枫叶 于 2011-7-24 12:23 编辑
仰望天上的光 发表于 2011-7-23 22:25
我的程序有问题,改2个地方:
(1)38行改为int priNumber = 2;因为我从5开始检测,5之前已经有2个素数2和 ...

的确很厉害.不过我想问一下,是否可以再作如此修整
  1. void initTable()
  2. {
  3.         int i,j;
  4.         //for(i=3;i<=SQRT_NUMS;++i){
  5.         for(i=3;i<=SQRT_NUMS;i+=2)
  6.         {
  7.                 //vec[i - 1] = 1;
  8.                 vec[i + 1] = 1;
  9.                 if(vec[i]==0)
  10.                 {
  11.                         for(j=i*i;j<=NUMS;j+=2*i)
  12.                                 vec[j]=1;
  13.                 }
  14.         }
  15. }
  16. 我还是多此一举了。会错意了。
复制代码


想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
发表于 2011-7-24 16:36:17 | 显示全部楼层
冬冬 发表于 2011-7-23 22:44
我一直纳闷的是,我给你的代码添加了一个PrintTable函数,打印了2 - 100之间的素数,如下图。但是这个 ...

我在你修改仰望天上的光的基础,又进行了一点调整,可以统计极品素数的个数并输出预期的极品素数。
  1. #include <stdio.h>
  2. #include <stdlib.h>

  3. #define NUMS 100000
  4. #define SQRT_NUMS 318

  5. static int vec[NUMS+1];

  6. /*
  7. 筛法求素数
  8. (1)vec[i]==0则i为素数
  9. (1)vec中下标为偶数的肯定不是素数
  10. */
  11. void initTable();
  12. //计算极品素数的个数
  13. int count(int n);
  14. void PrintAndCount(int n)
  15. {
  16.     /* for(int i = 2;i <= n; i++)
  17.      {
  18.                 if(vec[i] == 0)  
  19.                         printf("%d\t",i);
  20.      }
  21.      printf("\n");*/
  22.         int result = 0;
  23.         int priNumber = 2;
  24.         for(int i = 3; i <= n; i++)
  25.         {
  26.                 if(vec[i] == 0)
  27.                 {
  28.                         if(i % 2 && vec[priNumber] == 0)
  29.                         {
  30.                                 printf("%d\t", i);
  31.                                 result++;
  32.                         }
  33.                         priNumber++;
  34.                 }
  35.         }
  36.         printf("\n共有%d个极品素数\n", result);
  37. }
  38. int main(int argc, char **argv)
  39. {
  40.         int number;
  41.         initTable();
  42.     while(scanf("%d", &number) != EOF)
  43.         {
  44.                 if(number == -1)
  45.                         break;
  46.                 PrintAndCount(number);
  47.         }
  48.         system("pause");
  49.         return 0;
  50. }

  51. void initTable()
  52. {
  53.         int i ,j, k;
  54.                 for(k = 4; k <= NUMS; k += 2)
  55.                 {
  56.                         vec[k] = 1;
  57.                 }
  58.         for(i = 3; i <= SQRT_NUMS; i += 2)
  59.                 {
  60.                         if(vec[i] == 0)
  61.                         {        
  62.                                 for(j = i * i; j <= NUMS; j += 2 * i)
  63.                                         vec[j] = 1;
  64.             }
  65.         }
  66. }
复制代码


想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
 楼主| 发表于 2011-7-24 17:09:50 | 显示全部楼层
紫色枫叶 发表于 2011-7-24 16:36
我在你修改仰望天上的光的基础,又进行了一点调整,可以统计极品素数的个数并输出预期的极品素数。

他的筛法,是转为此题而设计的。
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
发表于 2011-7-24 19:21:01 | 显示全部楼层
楼主,,,  那个2好像也是极品素数吧
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
 楼主| 发表于 2011-7-24 21:53:04 | 显示全部楼层
断点 发表于 2011-7-24 19:21
楼主,,,  那个2好像也是极品素数吧

我们的题目,第一个素数是2,不是从1开始的。虽然有些书上说1也是素数
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
发表于 2011-7-24 23:50:12 | 显示全部楼层
素数 只能被1和他本身整除的数
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
发表于 2011-7-25 19:05:45 | 显示全部楼层
可惜我连素数是什么都不知道
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
发表于 2011-8-12 02:39:04 | 显示全部楼层
后悔当年没有好好学数据结构O(∩_∩)O~
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
发表于 2011-10-13 00:31:46 | 显示全部楼层
#include<stdio.h>
#include<math.h>
int f(int n)
{
        int i,j,count=1;
        for(i=3;i<=n;i++){
                for(j=2;j<=sqrt(n);j++)
                        if(i%j==0) break;
                        if(j>=sqrt(n)) count++;
        }
        return count;
}
int main()
{
        int N,M;
        scanf("%d",&N);
        M=f(N);
        printf("%d\n",f(M));
        return 0;
}
       
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
发表于 2012-6-16 01:05:06 | 显示全部楼层
见识咯 都是大神啊 高手 继续努力
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
发表于 2012-7-27 09:59:23 | 显示全部楼层
呵呵。。。  极品素数?  头一次听说  顶一个0.0
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

小黑屋|手机版|Archiver|鱼C工作室 ( 粤ICP备18085999号-1 | 粤公网安备 44051102000585号)

GMT+8, 2024-4-26 12:02

Powered by Discuz! X3.4

© 2001-2023 Discuz! Team.

快速回复 返回顶部 返回列表