算法—素数的判断
1.判断一个数是否为素数
bool judge01(int num)
{
for (int i = 2; i <= sqrt(num); i++) {
if (num % i == 0) {
return false;
}
}
return true;
}
2.筛法生成素数表
#include <iostream>
#include<math.h>
#define max 2000
using namespace std;
int num[2000] = { 0 };
int prime[1000] = { 0 };
int main()
{
int i, j, k = 0;
for (i = 2; i < max; i++) {//从i开始遍历
if (!num[i]) {
for (j = i + i; j < max; j += i) {//但凡是i的倍数全部剔除,将对应数组下标元素置为1
num[j] = 1;
}
prime[++k] = i;//将i保存至素数表
}
}
for (i = 0; i < k; i++) {//看用来记录素数表的大小
cout << prime[i] << endl;
}
return 0;
}
3.六元素法
六素数,是相差为6的素数偶( p , p + 6 ),例如:
(5,11), (7,13), (11,17), (13,19), (17,23)…
由以上可以观察出,我们在求解素数的时候其实可以每次走的步数为6,这样和每次步长为一比起来可以大大节省时间
int prime02( int num )
{
if(num <= 1)//
return 0;
if( num == 2 || num == 3 || num == 5 )
return 1;
if(num%2 == 0 || num%3 == 0 )
return 0;
for(int i=5; i<=sqrt(num); i += 6 ){
if( num % i == 0 || num % (i+2) == 0 )
return 0;
}
return 1;
}
例题:
题目描述
有n盏灯,序号为1到n。在初始状态下,所有的开关都是关的。 有n个开关控制这n盏灯,第i个开关控制第i盏灯。
现在从1开始计数,每遇到一个素数就把该素数对应的倍数序号的开关朝相反的方向拨一下,一直到最后一个小于等于n的素数为止。请统计最后有多少盏灯是开的?
输入
多组输入,每组输入一个n(2<=n<=106)。
输出
每组数据,输出开的灯的盏数
**样例输入 **
10
样例输出
7
问题代码:
#include <iostream>
#include <cstring>
#include <cstdio>
#include <cmath>
using namespace std;
int light[1000000] = { 0 };
int prime(int num)//1.基本方法
{
for (int i = 2; i <= sqrt(num); i++) {
if (num%i == 0) {
return 0;
}
}
return 1;
}
int main()
{
int n;
while (scanf_s("%d", &n) != EOF) {
memset(light, 0, sizeof(light));//置0函数不可缺
//int light[1000000] = { 0 };//此时定义在主函数里面,当数组大小太大编译器会报错
for (int i = 2; i <= n; i++){
int Prime = prime(i);
if (Prime) {
//cout << i << endl;
for (int j = 1; j*i <= n; j++) {
if (light[j*i] != 1) {
light[j*i] = 1;
}
else
light[j*i] = 0;
}
}
}
int sum = 0;
for (int i = 1; i <= n; i++) {
if (light[i]) {
sum++;
}
}
cout << sum << endl;
}
return 0;
}
报错截图:
猜测原因是定义在函数里面,数据存放在栈区,申请内存过大超出编译器限值;当定义为全局变量是数据存放在全局区
较大的数组尽量定义在全局范围
问题分析: 即使如此还应和考虑问题的时限,就应该使用六素数法
#include <iostream>
#include <cstdio>
#include <cstring>
#include <cmath>
using namespace std;
int light[1000050] = { 0 };
int prime(int num)
{
if (num < 2)return 0;
if (num == 2 || num == 3 || num == 5)return 1;
if (num % 2 == 0 || num % 3 == 0)return 0;
for (int i = 5; i <= sqrt(num); i += 6) {
if (num%i == 0 || num % (i + 2) == 0) {
return 0;
}
}
return 1;
}
int main()
{
int n;
while (scanf_s("%d", &n) != EOF) {
memset(light, 0, sizeof(light));//置0函数不可缺
for (int i = 2; i <= n; i++)
{
int Prime = prime(i);
if (Prime) {
//cout << i << endl;
for (int j = 1; j*i <= n; j++) {
if (light[j*i] != 1) {
light[j*i] = 1;
}
else
light[j*i] = 0;
}
}
}
int sum = 0;
for (int i = 1; i <= n; i++) {
if (light[i]) {
sum++;
}
}
cout << sum << endl;
}
return 0;
}
总结:
1.考虑数组的大小,较大时定义在全局范围
2.求素数优先考虑六素数法,高效
3.数组置0用memset()函数,不要忘记包含头文件