题意简述
题目要求找出1到10000内数,有多少个素数组成的总数;比如3只有自己那就是3,比如41有2+3+5+7+11+13, 11+13+17,和41,那就是三个(加起来数是连续的素数)
算法分析
主要还是考验如何高效快速的得到素数表.下来就是如何得到开始计算的下标和把所有相加可能得出来。我先用的是朴素的,思考部分加上一些很高效的算法
程序样例
unsigned short IsPrime(unsigned short num) { register unsigned short i=2; while(i*i <= num) { if(num % i == 0) break; else ++i; } if(i*i <= num) return 0; return 1; } int main() { unsigned short i,j,k,counter,tnum,sum; unsigned short num[670]; for(i=2,j=0;i<5000;++i) { if(IsPrime(i)) num[++j]=i; } num[0]=j; printf("%u\n",sizeof(short)); while(1) { scanf("%hu",&tnum);//between 2 and 10000 if(tnum == 0) return 0; counter=0; if(tnum > 4999) { i=num[0]; if(IsPrime(tnum)) ++counter; } else { for(i=1;i<num[0];++i) { if(num[i] == tnum) ++counter; if(num[i] >= tnum) { --i; break; } } } for(k=i;k>0;--k) { for(j=i,sum=0;j>0;--j) { sum+=num[j]; if(sum == tnum) ++counter; if(sum >= tnum) { --i; break; } } } printf("%hu\n",counter); } return 0; }
流程:
先把5000内素数,存入数组中,期间算法就是用FOR+朴素的取余判断(效率不高)。下来找到比需要查询数小的数的下标。用来循环判断组成可能。
NOTE:为什么是5000内呢,因为5000以上的数单独判断就行,要组成的话肯定是两个加和小于10000的组合,所以5000内就够用了
下来就是两层循环,从刚才下标开始往前加,大了就从前一个重来。直到开始下标小于1
指标:
POJ评定 176K 16MS(诡异的是第一次没改前是0MS)
思考
朴素的判断素数确实效率不高,经大大指导 知道了快速点的方法
筛选法
思路是,要求10000以内的所有素数,把1-10000这些数都列出来,1不是素数,划掉;2是素数,所有2的倍数都不是素数,划掉;取出下一个幸存的数,划掉它的所有倍数;直到所有幸存的数的倍数都被坏掉为止。完成了就可以直接用a[n]
== 1来判断素数了 效率确实很高
int i, tmp; int a[10000] 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; } } }
不过这样出来的素数数组是离散的 中间有很多0 算加和的话,不知道影响大不。但是总体上肯定比我写的效率高~